`

01-Struts1.3 CRUD

阅读更多

 Struts作为MVC模式的典型实现,对ModelViewController都提供了对应的实现组件如图:

 

 

根据上图,总结Struts架构的工作原理

          Model部分:

                  StrutsModel部分由ActionForm JavaBean组成,其中,ActionForm用于封装用户请求参数,所有的用户请求参数由系统自动封装成ActionForm对象;该对象被ActionServlet转发给Action;然后Action根据ActionForm里的请求参数处理用户请求;JavaBean封装了底层的业务逻辑,包括数据库访问等等,在更复杂的应用中,JavaBean所代表的绝非一个简单的JavaBean,可能是EJB组件或者其他的业务逻辑组件;

         View部分:

                   StrutsView部分采用JSP实现,Struts提供了丰富的标签库,通过这些标签库可以最大限度地减少脚本的使用,这些自定义的标签库可以实现与Model的有效交互,并增加了显示功能;

                   整个应用由客户端请求驱动,当客户端请求被ActionServlet拦截时,ActionServlet根据请求决定是否需要调用Model处理用户请求,当用户请求处理完成后,其处理结果通过JSP呈现给用户;

        Controller部分

                   StrutsController由两部分组成,一是系统核心控制器,另一个是业务逻辑控制器

                   系统核心控制器对应上图的ActionServlet,该控制器由Struts框架提供,继承HttpServlet类,因此可以配置一个标准的Servlet。该控制器负责拦截所有HTTP请求,然后根据用户请求决定是否需要调用业务逻辑控制器,如果需要调用业务逻辑控制器,则将请求转发给Action处理,否则直接转向请求的JSP页面;

                   业务逻辑控制器负责处理用户请求,但其本身不具有处理功能,而是调用Model来完成处理,他对应上图的Action部分;

 

Struts1的流程:

 

Struts框架中所使用的组件: 

       1ActionServlet: 核心控制器(工作构建数据结构流程)  

       2Action.Class 包含事务逻辑  

       3ActionForm :ActionForm:封装用户请求的参数  (显示模块数据)  

       4ActionMapping: 用于封装请求处理流程的关系(帮助控制器将请求映射到操作)   

       5ActionForward :封装响应(用来指示操作转移的对象)  

       6ActionError: 用来存储和回收错误  

       7Struts标记库: 可以减轻开发显示层次的工作

 

Struts1的开发步骤:

         1、将Struts1下的包添加到lib

         2、在web.xml中配置核心控制器

         3、生成Struts的配置文件

         4、生成相应的actionmodel以及jsp

下面我们先来以Struts1.2+JDBC CRUD Demo为例

整体目录结构为:

 

 

 一、web.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	version="2.5"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<servlet>
		<servlet-name>actionServlet</servlet-name>
		<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
		<init-param>
			<param-name>config</param-name>
			<param-value>/WEB-INF/struts-config.xml</param-value>
		</init-param>
		<init-param>
			<param-name>debug</param-name>
			<param-value>3</param-value>
		</init-param>
		<init-param>
			<param-name>detail</param-name>
			<param-value>3</param-value>
		</init-param>
		<load-on-startup>0</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>actionServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<!-- 过滤器 -->
	<filter>
		<filter-name>encoding</filter-name>
		<filter-class>com.iflytek.filter.EncodingFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>encoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

说明:

web.xml中,所有.do结尾的请求都将有ActionServelt拦截,同时该Servlet还有加载Struts配置文件的责任ActionServelt默认加载web-inf路径下,或者改变了文件名,则应采用下方式配置:

 

<servlet>
<servlet-name>actionServelt</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/myConfig.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>actionServelt</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

这样指定了ActionServlet的配置文件myConfig.xml文件,最为init-param参数载入,载入时指定了参数名config,为固定值,configStruts固定的参数名,struts负责解析该参数,并加载该参数指定的配置文件。当有多个Struts配置文件时,只需添加init-param元素即可

<init-param>
	<param-name>config</param-name>
	<param-value>/WEB-INF/myConfig1.xml</param-value>
</init-param>
<init-param>
	<param-name>config/first</param-name>
	<param-value>/WEB-INF/myConfig2.xml</param-value>
</init-param>

 

二、ActionFrom

 

package com.iflytek.struts.form;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.upload.FormFile;

import com.iflytek.vo.User;

/**
 * @author xudongwang 2011-10-20
 * 
 */
@SuppressWarnings("serial")
public class UserForm extends ActionForm {
	private int cp = 1;
	private int ls = 5;

	// user.do?status=list
	private String status;

	// 这里使用对象接受,这里必须new出来,否则设不上值
	private User user = new User();

	// 当使用struts需要进行文件上传操作时,需要在Struts的ActionForm通过一个类型为FormFile的对象来接受文件的内容
	private FormFile img;

	/**
	 * Method validate
	 * 
	 * @param mapping
	 * @param request
	 * @return ActionErrors
	 */
	public ActionErrors validate(ActionMapping mapping,
			HttpServletRequest request) {
		// 注意需要判断状态,并不是所有情况都需要验证

		ActionErrors errors = new ActionErrors();
		if ("insert".equals(status)) {
			if (this.user.getAccount() == null
					|| this.user.getAccount().trim().equals("")) {
				errors.add("accout", new ActionMessage("account.null"));
			}
			if (this.img == null || this.img.getFileSize() == 0) {
				errors.add("img", new ActionMessage("img.null"));
			} else if (this.img.getFileSize() > 1024000) {
				errors.add("img", new ActionMessage("img.size"));
			} else {
				this.user.setPostDate(new Date());
				String fileName = new Date().getTime() + "";
				// 文件扩展名,从最后一个点开始截取字符串
				String kz = this.img.getFileName().substring(
						this.img.getFileName().lastIndexOf("."));
				this.user.setPhoto(fileName + kz);
			}
		}
		return errors;
	}

	/**
	 * Method reset
	 * 
	 * @param mapping
	 * @param request
	 */
	public void reset(ActionMapping mapping, HttpServletRequest request) {
	}

	public int getCp() {
		return cp;
	}

	public void setCp(int cp) {
		this.cp = cp;
	}

	public int getLs() {
		return ls;
	}

	public void setLs(int ls) {
		this.ls = ls;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public FormFile getImg() {
		return img;
	}

	public void setImg(FormFile img) {
		this.img = img;
	}
}

 说明:

配置ActionForm,需要包含ActionForm类才可以,Struts1要求ActionForm必须继承Struts的基类org.apache.struts.action.ActionFormActionForm的实现非常简单,该类只是一个普通的JavaBean,只要为每个属性提供对应的gettersetter方法即可。

ActionForm用于封装用户的请求参数,而请求参数是通过JSP页面的表单域传递过来的,所以要保证ActionForm的参数属性的gettersetter后缀名字与表单域的名字相同,而与属性名无关,可以随意取(即客户端请求中有个属性名为name,则在JavaBean中需要getNamesetName,而该JavaBean属性名可以任意,因为属性为private的,所以是通过构造器取的);

 

三、Action

 

package com.iflytek.struts.action;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

import com.iflytek.factory.DAOFactory;
import com.iflytek.struts.form.UserForm;
import com.iflytek.vo.User;

/**
 * DispatchAction:分发Action用来解决在Action中需要判断当前操作状态的问题,
 * 使用分发Action后可以根据传递状态参数自动调用对应的方法
 * 
 * @author xudongwang 2011-10-20
 * 
 */
public class UserAction extends DispatchAction {

	/**
	 * Method list 方法名list根据页面传入的status=list
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 */
	public ActionForward list(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		UserForm userForm = (UserForm) form;
		List<User> users = null;
		int allRecorders = 0;
		try {
			users = DAOFactory.getUserDAOInstance().findAll(userForm.getCp(),
					userForm.getLs());
			allRecorders = DAOFactory.getUserDAOInstance().getAllCount();
		} catch (Exception e) {
			e.printStackTrace();
		}
		request.setAttribute("cp", userForm.getCp());
		request.setAttribute("ls", userForm.getLs());
		request.setAttribute("users", users);
		request.setAttribute("allRecorders", allRecorders);
		return mapping.findForward("userlist");
	}

	public ActionForward insert(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		UserForm userForm = (UserForm) form;
		boolean flag = false;
		try {
			flag = DAOFactory.getUserDAOInstance().doCreate(userForm.getUser());
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (flag) {
			// 开始保存文件
			// 使用字节流FileOutputStream来输出上传的文件
			try {
				FileOutputStream os = new FileOutputStream(new File(this
						.getServlet().getServletContext().getRealPath("/")
						+ "upload/" + userForm.getUser().getPhoto()));
				os.write(userForm.getImg().getFileData());
				os.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

	    request.setAttribute("message", flag ? "添加成功!" : "添加失败!");
		request.setAttribute("path", "user.do?status=list");
		//return mapping.findForward("forward");
		
		//这里不使用struts进行页面的跳转
		ActionForward forward = new ActionForward();
		forward.setPath("/forward.jsp");
		return forward;	}
}

 说明:

         Action负责管理与之关联的ActionForm,它不仅需要配置实现类,还需要配置Acitonpath属性,用于被用户请求。

         1Action需要继承Aciton,并且重写execute方法

         2、通过ActionForm,可使Action无须从HTTP请求中解析参数,而直接从ActionForm中取

         Action的实现:

                   Action从转发过来的ActionForm中解析请求参数,对应的ActionForm则由ActionServlet在接受到用户请求时,负责实例化

                   实际过程是,ActionServlet拦截到用户请求后,根据用户的请求,在配置文件中查找对应的ActionAction         name属性指定了用于封装请求参数的ActionForm,然后ActionServlet将创建默认的ActionForm实例,并调用对应的         setter方法完成ActionForm的初始化;

         在上面的过程中,ActionServlet采用反射机制来完成对象的创建以及初始化等过程;

 

四、struts-config.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
	<!-- 业务逻辑控制器,处理用户请求,但其本身不具有处理功能,而是调用Model来完成处理 -->
<struts-config>
	<!-- 以下配置是针对ActionForm,form-beans中包含多个form-bean -->
	<form-beans>
		<form-bean name="userForm" type="com.iflytek.struts.form.UserForm" />
	</form-beans>

	<!-- 公共异常的处理,开发中使用不多 -->
	<global-exceptions>
		<exception key="num" type="java.lang.NumberFormatException" path="excep"></exception>
	</global-exceptions>

	<!-- 公共的跳转路径 -->
	<global-forwards>
		<forward name="excep" path="error.jsp"></forward>
	</global-forwards>

<!--
		以下配置是针对于Action,
		action-mappings用于封装请求处理流程的关系(帮助控制器将请求映射到操作)可以包含多个Action
	-->
	<action-mappings>
		<action attribute="userForm" input="/error.jsp" name="userForm"
			parameter="status" path="/user" scope="request"
			type="com.iflytek.struts.action.UserAction" cancellable="true"  unknown="true">
			<forward name="userlist" path="/UserList.jsp"></forward>
			<forward name="forward" path="/forward.jsp"></forward>
		</action>
	</action-mappings>
	<!-- 资源文件 所在的路径,资源文件的后缀名必须为properties-->
	<message-resources parameter="com.iflytek.struts.Resources" />
</struts-config>
说明:

1parameter名表示页面传参的名称status=list

2、一个action只能对应一个actionform,而一个actionform可以有多个action使用;

3input用来作错误页的,当validate方法执行后有错误,则自动跳转到该页;

4、所有struts-config.xml中配置的路径必须先加/,表示路径从webroot下开始定义

         5path表示该action的虚拟路径,必须加/,而不需要加.do的后缀

         6scope表示Action的属性方法,request表示每次请求都重新建立新的action

         7type表示Action的包.类名;

8、在action中可以包含多个不同的forward路径,而Forward分局部和全局两种,前者是在Action里配置,仅对该Action有效,后者单独配置,对所有的Action都有效,当每个Action在转发时,首先在局部Forward中查找与之对应的Forward,如果没找到,则才会到全局中查找,所以局部Forward可以覆盖全局Forward

         9forward中的nameforward的唯一标识,在action代码中执行跳转时需要通过该name来查找对应的路径,path表示真正跳转的路径;

         10redirect:设置是否使用重定向,只能是truefalse两个值;

         11unknown="true"表示如果没有xx.do则会跳转到错误页面

 

五、JSP

insert.jsp

 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
		<title>添加人员</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="description" content="This is my page">
	</head>
	<body>
		<center>
			<form action="user.do" method="post" enctype="multipart/form-data">
				用户名:
				<input type="text" name="user.account" />
				<br />
				密码:
				<input type="text" name="user.password" />
				<br />
				性别:
				<input type="radio" name="user.sex" value="男" checked="checked" />
				男
				<input type="radio" name="user.sex" value="女" />
				女
				<br />
				真实姓名:
				<input type="text" name="user.realName" />
				<br />
				照片:
				<input type="file" name="img" />
				<br />
				<input type="hidden" name="status" value="insert">
				<input type="submit" value="添加">
			</form>
		</center>
	</body>
</html>


UserList.jsp

 

<%@ page language="java" pageEncoding="UTF-8"%>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html:html lang="true">
<head>

	<title>用户列表</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="description" content="This is my page">

</head>

<body>
	<center>
	<a href="insert.jsp">添加人员</a><br/>
		<table border="1" width="60%">
			<tr>
				<td>
					用户名
				</td>
				<td>
					性别
				</td>
				<td>
					注册日期
				</td>
				<td>
					照片
				</td>
				<td>
					操作
				</td>
			</tr>
			<logic:present name="users" scope="request">
				<logic:iterate id="user" name="users" scope="request">
					<tr>
						<td>
							${user.account }
						</td>
						<td>
							${user.sex }
						</td>
						<td>
							<bean:write name="user" property="postDate" format="yyyy-MM-dd" />
						</td>
						<td>
							<img alt="${user.account }" src="upload/${user.photo }" width="80px" height="60">
						</td>
						<td>
							<a href="#">修改</a>  <a href="#">删除</a>
						</td>
					</tr>
				</logic:iterate>
			</logic:present>
		</table>

		<jsp:include page="split_page.jsp">
			<jsp:param name="currentPage" value="${cp}" />
			<jsp:param name="lineSize" value="${ls}" />
			<jsp:param name="allRecorders" value="${allRecorders}" />
			<jsp:param name="searchFlag" value="FALSE" />
			<jsp:param name="lineSizeFlag" value="TRUE" />
		</jsp:include>
	</center>
</body>
</html:html>

 

  • 大小: 24.3 KB
  • 大小: 14.8 KB
  • 大小: 12.2 KB
分享到:
评论

相关推荐

    struts1.3+spring3.0+hibernate3.3简单项目示例

    Struts1.3、Spring3.0和Hibernate3.3是经典的Java企业级开发框架组合,常被用于构建Web应用程序。这个"SSH"项目示例旨在帮助开发者理解如何将这三个框架整合并应用于实际项目中。下面我们将深入探讨这三个组件以及...

    Struts1.3+Spring4.x+Hibernate4.x框架整合实现对书籍的增删改查(含分页)

    Struts1.3、Spring4.x和Hibernate4.x是经典的Java Web开发框架组合,被称为SSH。这个项目展示了如何将这三个框架整合起来,实现一个完整的书籍管理应用,包括书籍的增加、删除、修改和查询功能,并且包含了分页展示...

    crud-struts:带有 struts 和 1.3 hibernate 的项目

    本项目名为"crud-struts",其核心是结合了Struts 1.3框架和Hibernate ORM(对象关系映射)工具,为开发者提供了一个基础的Java Web应用程序模板。Struts作为经典的MVC(模型-视图-控制器)框架,主要负责处理HTTP...

    毕设的酒店管理系统(Struts1.3+Hibernate3)

    在本项目中,系统采用Struts1.3作为MVC(Model-View-Controller)框架,用于处理用户请求和业务逻辑,而Hibernate3作为对象关系映射(ORM)工具,负责数据库操作和数据持久化。 Struts1.3是Apache基金会的一个开源...

    Struts1.3_Spring3.0_hibernate3.3示例

    Struts1.3_Spring3.0_Hibernate3.3示例是一个综合性的项目,它展示了如何在Java Web开发中整合三个流行的技术框架:Struts1.3、Spring3.0和Hibernate3.3。这些框架分别负责MVC(Model-View-Controller)架构、依赖...

    Struts1.3+spring2.5+JPA(hibernate) demo

    Struts1.3、Spring2.5和JPA(基于Hibernate)是Java Web开发中三个重要的框架,它们的集成使用可以构建出强大的企业级应用。这个"Struts1.3+spring2.5+JPA(hibernate) demo"提供了一个实践性的学习案例,帮助初学者...

    Struts1.3项目开发文档

    ### Struts1.3项目开发知识点详述 #### 一、环境搭建与配置 ##### 1.1 软件的下载与安装 在进行Struts1.3项目开发前,首先需要准备以下软件环境: - **JDK**: Java Development Kit,是Java编程语言的基础,用于...

    JavaWeb需要用到的jar包_jar包_javaweb_commons-dbutils-1.3_

    1. **commons-dbutils-1.3**: Commons-DbUtils是Apache的一个开源项目,它提供了一个简单且实用的数据库操作工具包。DbUtils的主要功能包括:连接池管理、SQL执行、结果集处理等。DbUtils与JDBC结合使用,可以避免...

    struts1.3 demo

    通过分析这个"struts1.3 demo",开发者可以深入理解Struts1的工作原理,学习如何组织一个简单的CRUD(创建、读取、更新、删除)应用,同时掌握处理乱码问题的方法,这对于理解Web应用的开发流程和架构设计具有重要...

    bbs论坛用struts1.3 hibernate3.2 spring2.5整合及oracle数据库

    在这个“bbs论坛”项目中,开发者选择了Struts1.3作为表现层框架,Hibernate3.2作为持久化层框架,Spring2.5作为业务逻辑和依赖注入框架,并结合Oracle数据库来存储数据。 Struts1.3是MVC(Model-View-Controller)...

    网上书店毕业论文(使用了jsp struts1.3 Hibernate)

    网上书店毕业论文主要探讨了一个基于B/S架构的网上图书城系统的设计与实现,该系统采用了Java Web技术,包括JSP、Struts 1.3框架和Hibernate ORM框架,以及MySQL数据库。以下是系统的详细分析和解释: 1. **B/S架构...

    Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案二

    在集成方案中,Hibernate将负责数据访问,通过映射Java对象到数据库表,实现数据的CRUD操作。 最后,Struts是表现层框架,主要处理HTTP请求并生成响应。Struts 1.3.8虽然相对较老,但依然广泛使用,它通过Action和...

    struts demo

    在这个"Struts1.3"的示例中,我们将探讨如何使用Struts1.3版本来实现一个简单的用户留言和查看留言的功能,并与Oracle数据库进行交互,同时利用连接池管理和DBUtils包来优化数据库操作。 **1. Struts1.3框架介绍** ...

    ssh strus1.3集成

    在这个"ssh struts1.3集成"的主题中,我们将深入探讨这三个组件的集成以及相关的知识点。 1. **Struts 1.3**: - **Model**: Struts框架的核心是ActionServlet,它作为控制器处理HTTP请求,调用业务逻辑(模型层)...

    spring-hibernate-dwr实例

    spring-hibernate-dwr做的AJAX操作CRUD实例 环境:myeclipse6.0+jdk1.6 所需lib列表,请自行加入 mysql-connector-java-3.1.7-bin.jar antlr-2.7.6rc1.jar asm-attrs.jar cglib-2.1.3.jar ...

    Struts+Spring+Hibernate--SSH整合实例.

    对于Struts,我们需要选择Struts 1.3规范,并设置基础包为`edu.syict.struts`。接下来,添加Spring支持时,选择Spring 2.0的相关库,并将它们复制到项目文件夹。最后,添加Hibernate支持时,选择Hibernate 3.1核心库...

    ActionServlet demo

    这个项目可能与Struts 1.3框架相结合,Struts是一个广泛使用的MVC(模型-视图-控制器)框架,用于构建企业级Java Web应用。 首先,让我们深入了解Servlet的基础知识。Servlet是Java编程语言中的一个接口,它允许...

    毕业设计物业管理系统(java版)

    这个系统采用的是经典的MVC架构模式,利用Struts1.3作为表现层框架,Hibernate3.2作为持久层框架,以及jQuery库来增强前端交互体验,数据库则选择了MySQL,提供数据存储和管理功能。 1. **Struts1.3**:Struts是...

    Struts+Spring+Hibernate整合开发框架搭建指南

    SSH(Struts1.3+Spring2.0+Hibernate3.1)是一个经典的Java Web开发框架,用于构建高效、可扩展的企业级应用。这个框架整合了三个强大的开源框架:Struts作为表现层,Spring作为控制层和业务层,以及Hibernate作为...

    MyBlogStrutsHibernateExample

    Blog Application using Struts/Hibernate A small blogging web application demonstrating the use of a Struts 1.3 UI and Hibernate persistence technologies to implement common entity CRUD operations.

Global site tag (gtag.js) - Google Analytics