基于SSH框架的后台开发流程

Posted by Johnnwen on May 18, 2016

代码框架图

SSHStructure

基本开发流程

1.加入Spring

1)加入jar包
2)配置web.xml文件
3)加入Spring配置文件

2.加入Hibernate

1)同时建立持久化类,和其对应的.hbm.xml文件,生成对应的数据表

2) Spring整合Hibernate

	a)加入jar包
	b)在类路径下加入Hibernate.cfg.xml文件,在其中配置Hibernate的基本属性
	c)建立持久化类和其对应的.hbm.xml文件
	d)和Spring进行整合
		i)加入 从c3p0和MySql的驱动
		ii)在Spring的配置文件中配置:数据源,SessionFactory,声明式事务
	e)启动项目,会看到生成的数据包

3.加入Struts2

1) 加入jar包,   如果有重复的jar包,则删除版本低的
2) 在web.xml文件中配置Struts2 的Filter
3) 加入Struts2的配置文件
4) 整合Spring
	a)加入Struts2的Spring插件的jar包
	b)在spring的配置文件中正常配置Action,注意Action的Scope为prototype(非单例)
	c)在Struts2的配置文件中配置Action时,class属性指向该Action在IOC中id

4.完成功能

1. 获取所有的员工信息:如果在DAO中只查询Employee的信息,而且Employee和Department还是使用的懒加载:

	页面上还需要显示员工信息,此时会出现懒加载异常,代理对象不能被初始化:org.hibernate.LazyInitializationException

解决方案:

	a)  打开懒加载:不推荐使用,增加了sql查询语句
		<many-to-one name="department" class="com.wyw.shh.entities.Department" lazy="false">
	   	<column name="DEPARTMENT_ID" />
		</many-to-one>
	b)获取Employee时使用迫切左外连接同时初始化关联的Department对象
		FROM Employee e LEFT OUTER JOIN FETCH e.department
	c)使用OpenSessionInFilter:在页面加载完开Session

2.删除员工信息:

	a) 正常删除,返回值是redirect类型,而且重定向到emp-list
	b) 确定要删除吗?的提示使用jQuery完成
	c)Ajax的使用参见struts-2.3.15.3/docs/WW/docs/ajax.html
	
3.添加员工
	a)显示表单页面,需要先查询所有的部门信息
	b)显示使用struts2的ModelDriven和Preparable拦截器(点击提交的时候把表单封装成一个对象)
	c)时间是一个字符串,需要转为一个Data类型的对象

核心代码

配置文件
  1. applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

	<!-- 导入资源文件-->
	<context:property-placeholder location="classpath:db.properties"/>
	
	<!-- 配置c3p0数据源 -->
	
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="driverClass" value="${jdbc.driverClass}"></property>
		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
		
		<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
		<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
	</bean>

	<!-- 配置SessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
		<property name="mappingLocations" value="classpath:com/wyw/shh/entities/*hbm.xml"></property>
	</bean>
	
	<!-- 配置Spring的声明式事务 -->
	<!-- 1.配置Hibernate的事务管理器 -->
	
	<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	
	<!-- 2.配置事务属性 -->
	<tx:advice id="txAdvie" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="LastNameIsValid" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 3.配置事务切入点,再把事务属性和事务切入点关联起来 -->
	<aop:config>
		
		<aop:pointcut expression="execution(* com.wyw.ssh.service.*.*(..))" id="txPointcut"/>
		<aop:advisor advice-ref="txAdvie" pointcut-ref="txPointcut"/>
	</aop:config>
</beans>

  1. applicationContext-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	
	<bean id="employeeDao" class="com.wyw.ssh.dao.EmployeeDao">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<bean id="employeeService" class="com.wyw.ssh.service.EmployeeService">
		<property name="employeeDao" ref="employeeDao"></property>
	</bean>
	
	
	<bean id="departmentDao" class="com.wyw.ssh.dao.DepartmentDao">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<bean id="departmentServie" class="com.wyw.ssh.service.DepartmentServie">
		<property name="departmentDao" ref="departmentDao"></property>
	</bean>
	
	<bean id="employeeAction" class="com.wyw.shh.actions.EmployeeAction"
		scope="protoatype">
		<property name="employeeService" ref="employeeService"></property>
		<property name="departmentServie" ref="departmentServie"></property>
	</bean>

</beans>
  1. hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
    
    <!-- 配置Hibernate的基本属性 -->
    
    <!-- 方言 -->
    
    <property name="hibernate.dialect" >org.hibernate.dialect.MySQL5InnoDBDialect</property>
    
    <!-- 是否显示及格式化SQL -->
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    
    <!-- 生成数据表的策略 -->
    <property name="hibernate.hbm2ddl.auto">update</property>
    
    <!-- 二级缓存 -->
    
    </session-factory>
</hibernate-configuration>

  1. struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
	<constant name="struts.devMode" value="false" />  
	
	<constant name="struts.action.extension" value="action,do,html,"></constant>
	
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
	
	<constant name="struts.ui.theme" value="xhtml"></constant>

	<!-- 
		package:组织模块
		name:用于其他包应用当前包
		extends:当前包继承的包
	 -->
	<package name="product" extends="struts-default" namespace="/">
	
		<!-- 定义新的拦截器栈,配置prepare拦截器栈的参数值alwaysInvokePrepare为false -->
	
		<interceptors>
			<interceptor-stack name="sshStack">
				<interceptor-ref name="paramsPrepareParamsStack">
					<param name="prepare.alwaysInvokePrepare">false</param>
				</interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<!-- 使用新的拦截器栈 -->
		<default-interceptor-ref name="sshStack"></default-interceptor-ref>
		
		<!-- 配置一个action -->
		
		<action name="test" class="com.wyw.shh.actions.EmployeeAction"
			method="test">
			<result name="test">/WEB-INF/views/success.jsp</result>
		</action>
		
		

		
		<action name="emp-*" class="com.wyw.shh.actions.EmployeeAction"
			method="{1}">
			<result name="{1}">/WEB-INF/views/emp-{1}.jsp</result>
			<result type="stream" name="ajax-success">
		        <param name="contentType">text/html</param>
		        <param name="inputName">inputStream</param>
		    </result>
			<!--<result name="success" type="redirect">/emp-list</result>-->
			<result name="success" type="redirect">/emp-list</result>
		</action>
	</package>
  
</struts>
  1. xwork-conversion.properties
java.util.Date=com.wyw.shh.converters.SSHDateConverters
  1. java.util.Date=com.wyw.shh.converters.SSHDateConverters
jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring

jdbc.initPoolSize=5
jdbc.maxPoolSize=10
  1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	
	
	<!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext*.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	 <!-- 配置Struts2的Filter -->
	<filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    
     <welcome-file-list>
        <welcome-file>/WEB-INF/views/index.jsp</welcome-file>
    </welcome-file-list>
	

</web-app>
持久化类
  1. com.wyw.shh.entities

(1)Department.java

package com.wyw.shh.entities;

public class Department {

	private Integer id;

	private String departmentName;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getDepartmentName() {
		return departmentName;
	}

	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

	

}

(2) Employee.java

package com.wyw.shh.entities;

import java.util.Date;

public class Employee {

	private Integer id;
	//不能被修改
	private String lastName;
	private String email;

	//从前端传入的是String类型,需要类型转化
	private Date birth;
	
	//不能被修改
	private Date createTime;
	
	//单项n-1的关联关系
	private Department department;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", birth=" + birth
				+ ", createTime=" + createTime + ", department=" + department + "]";
	}
	
	

}
  1. com.wyw.ssh.dao

(1) BaseDao.java

package com.wyw.ssh.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class BaseDao {
	private SessionFactory sessionFactory;
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public Session getSession(){
		return this.sessionFactory.getCurrentSession();
	}

}

(2) DepartmentDao.java

package com.wyw.ssh.dao;

import java.util.List;

import com.wyw.shh.entities.Department;

public class DepartmentDao extends BaseDao{
	
	public List<Department> getAll(){
		String hql = "FROM Department";
		return getSession().createQuery(hql).list();
	}

}

(3) EmployeeDao.java

package com.wyw.ssh.dao;

import java.util.List;

import org.hibernate.Query;

import com.wyw.shh.entities.Employee;

public class EmployeeDao extends BaseDao{
	public List<Employee> getAll(){
		
		String hql = "FROM Employee e LEFT OUTER JOIN FETCH e.department";
		return getSession().createQuery(hql).list();
	}
	
	public void delete(Integer id){
		String hql = "DELETE FROM Employee e WHERE e.id = ?";
		
		getSession().createQuery(hql).setInteger(0, id).executeUpdate();
	}
	
	public void saveOrUpdate(Employee employee){
		getSession().saveOrUpdate(employee);
	}
	
	public Employee getEmployeeByLastName(String lastName){
		
		String hql = "FROM Employee e WHERE e.lastName = ?";
		
		Query query = getSession().createQuery(hql).setString(0, lastName);
		
		return (Employee)query.uniqueResult();
		
	}
	
	public Employee get(Integer id){
		return (Employee) getSession().get(Employee.class, id);
		
	}
}

  1. com.wyw.ssh.service

(1) DepartmentServie.java

package com.wyw.ssh.service;

import java.util.List;

import com.wyw.shh.entities.Department;
import com.wyw.ssh.dao.DepartmentDao;

public class DepartmentServie {
	
	private DepartmentDao departmentDao;
	public void setDepartmentDao(DepartmentDao departmentDao) {
		this.departmentDao = departmentDao;
	}
	
	public List<Department> getAll(){
		return departmentDao.getAll();
	}

}

(2) EmployeeService.java

package com.wyw.ssh.service;

import java.util.List;

import com.wyw.shh.entities.Employee;
import com.wyw.ssh.dao.EmployeeDao;

public class EmployeeService {
	
	private EmployeeDao employeeDao;
	
	public void setEmployeeDao(EmployeeDao employeeDao) {
		this.employeeDao = employeeDao;
	}
	
	public List<Employee> getAll(){
		
		List<Employee> employees = employeeDao.getAll();
		
		//employees.clear();
		return employees;
	}
	
	public void delete(Integer id){
		employeeDao.delete(id);
	}
	
	public void saveOrUpdate(Employee employee){
		employeeDao.saveOrUpdate(employee);
	}
	
	public boolean LastNameIsValid(String lastName){
		return employeeDao.getEmployeeByLastName(lastName) == null;
	}
	
	public Employee get(Integer id){
		return employeeDao.get(id);
	}

}
  1. com.wyw.shh.actions

(1) EmployeeAction.java

package com.wyw.shh.actions;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.wyw.shh.entities.Employee;
import com.wyw.ssh.service.DepartmentServie;
import com.wyw.ssh.service.EmployeeService;


public class EmployeeAction extends ActionSupport implements RequestAware,
	ModelDriven<Employee>,Preparable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private EmployeeService employeeService;
	
	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
	
	private DepartmentServie departmentServie;
	public void setDepartmentServie(DepartmentServie departmentServie) {
		this.departmentServie = departmentServie;
	}
	
	public String list(){
		
		request.put("employees", employeeService.getAll());
		return "list";
	}
	
	private Integer id;
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	
	private InputStream inputStream;
    public InputStream getInputStream() {
        return inputStream;
    }
    
	public String delete(){
		try {
			employeeService.delete(id);
			inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
		} catch (Exception e) {
			try {
				inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
		return "ajax-success";
	}
	
	public String input(){
		request.put("departments", departmentServie.getAll());
		return "input";
	}
	
	public void prepareInput(){
		if(id != null){
			model = employeeService.get(id);
		}
	}
	
	public String save(){
		
		if(id == null){
			model.setCreateTime(new Date());		
		}
		employeeService.saveOrUpdate(model);
		//System.err.println(model);
		return SUCCESS;
	}
	
	public void prepareSave(){
		if(id == null){
			model = new Employee();			
		}else{
			model = employeeService.get(id);
		}
	}

	private String lastName;
	
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String validateLastName() throws UnsupportedEncodingException{
		if(employeeService.LastNameIsValid(lastName)){
			inputStream = new ByteArrayInputStream("1".getBytes("UTF-8"));
		}else{
			inputStream = new ByteArrayInputStream("0".getBytes("UTF-8"));
			
		}
		return "ajax-success";
	}
	
	private Map<String, Object> request;
	@Override
	public void setRequest(Map<String, Object> arg0) {
		this.request = arg0;
		
	}
	
	
	public String test(){
		
		System.out.println("test.....");
		return "test";
	}

	@Override
	public void prepare() throws Exception {
		
		
	}

	private Employee model;
	@Override
	public Employee getModel() {
		
		return model;
	}
	
	public Employee get(Integer id){
		return employeeService.get(id);
	}

}
  1. com.wyw.shh.converters

(1) SSHDateConverters.java

package com.wyw.shh.converters;

import java.util.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

public class SSHDateConverters extends StrutsTypeConverter{

	private DateFormat dateFormate;
	
	{
		dateFormate = new SimpleDateFormat("yyyy-MM-dd");
	}
	
	@Override
	public Object convertFromString(Map arg0, String[] arg1, Class arg2) {
		if(arg2 == Date.class){
			try {
				return dateFormate.parse(arg1[0]);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	@Override
	public String convertToString(Map arg0, Object arg1) {
		if(arg1 instanceof Date){
			return dateFormate.format((Date)arg1);
		}
		return null;
	}

}
JSP文件
  1. emp-input.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-2.2.3.min.js"></script>

<script type="text/javascript">

	$(function() {
		$(":input[name=lastName]").change(function() {
			var val = $(this).val();
			val = $.trim(val);
			var $this = $(this);
			if(val != ""){
				//把当前节点后面的所有的font兄弟节点清除
				
				$this.nextAll("font").remove();
				var url = "emp-validateLastName";
				var args = {"lastName":val,"time":new Date()};
				$.post(url,args,function(data){
					//表示可用
					if(data == "1"){
						$this.after("<font color='green'>LastName可用!</font>")
					//表示不可用
					}else if(data == "0"){
						$this.after("<font color='red'>LastName不可用!</font>")
						
					//服务器错误
					}else{
						alert("服务器错误")
					}
				});
				
			}else{
				alert("lastName不能为空");
			}
		});
	})

</script>
</head>
<body>
	<h4>Employee Input Page</h4>
	
	<s:form action="emp-save" method="post">
		<s:if test="id != null">
			<s:textfield name="lastName" label="LastName" disabled="true" > </s:textfield>
			<s:hidden name="id"></s:hidden>
			<%--
			<!--通过添加隐藏域的方式把未显式提交的字段值提交到服务器-->
			<s:hidden name="lastName"></s:hidden>
			<s:hidden name="createTime"></s:hidden>
			 --%>
		</s:if>
		<s:else>
			<s:textfield name="lastName" label="LastName"> </s:textfield>
		</s:else>
		<s:textfield name="email" label="Email"> </s:textfield>
		<s:textfield name="birth" label="Birth"> </s:textfield>
		
		<s:select list="#request.departments"
			listKey="id" listValue="departmentName" name="department.id"
			label="Department"></s:select>
			
		<s:submit></s:submit>	
	</s:form>
</body>
</html>
  1. emp-list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="s"  uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>

<script type="text/javascript" src="scripts/jquery-2.2.3.min.js"></script>
<script type="text/javascript">
	$(function(){
		//1.点击的delete时,弹出确定是要删除信息吗?若确定则执行删除,否则取消
		$(".delete").click(function() {
			//取消超链接的默认行为
			
			var lastName = $(this).next(":input").val();
			var flag = confirm("确定要删除" + lastName + " 的信息吗?");
			
			if (flag) {
				var $tr = $(this).parent().parent();
				//删除,使用ajax方式
				var url = this.href;
				var args = {"time":new Date()}
				$.post(url,args,function(data){
					//如果data的返回值为1,则提示删除成功,且把当前行删除
					if(data == 1){
						alert("删除成功");
						$tr.remove();
					}else{
						//否则,则提示删除失败
						alert("删除失败");
					}
					
				});
			}
			return false;
		})
		
	})
</script>
</head>
<body>

	<h4>Employee List Page</h4>
	
	<s:if test="#request.employees == null || #request.employees.size() == 0">
		没有任何员工信息
	</s:if>
	<s:else>
		<table border="1" cellpadding="1" cellspacing="0">
			<tr>
				<td>ID</td>
				<td>LASTNAME</td>
				<td>EMAIL</td>
				<td>BIRTH</td>
				<td>CREATETIME</td>
				<td>DEPT</td>
				<td>DELETE</td>
				<td>EDITE</td>
				
			</tr>
			
			<s:iterator value="#request.employees">
				<tr>
					<td>${id }</td>
					<td>${lastName }</td>
					<td>${email  }</td>
					<td>
						<s:date name="birth" format="yyyy-MM-dd"/>
					</td>
					<td>
						<s:date name="createTime" format="yyyy-MM-dd hh:mm:ss"/>
					</td>
					<td>${department.departmentName }</td>
					<td>
						<a href="emp-delete?id=${id }" class="delete">Delete</a>
						<input type="hidden" value="${lastName }"/>
					</td>
					<td>
						<a href="emp-input?id=${id }">Edite</a>
	
					</td>
				</tr>
					
			</s:iterator>
		</table>
	</s:else>

</body>
</html>
  1. index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a href="test">test</a>
	<br><br>
	<a href="emp-list">All Employees</a>
	<br><br>
	<a href="emp-input">Add New Employee</a>
</body>
</html>