第1章 Struts2快速入门
Struts2是在WebWork基础上发展起来的一个新的MVC框架,与Struts1没有太多关系。本章将通过简单案例帮助读者快速理解Struts2框架的工作原理、开发部署步骤以及主要优点。
1.1 Struts2概述
从名称上看,Struts2应该是Struts1版本的扩展和升级。实际上,Struts2和Struts1没有太多的关系。
Struts1最初是Apache Jakarta项目的一部分,后来作为一个开源的MVC框架存在。Struts1曾经被很多Web应用采用,作为构建MVC的基础框架使用。Struts1最大的特点是提供了JSP标记库以及页面导航。
Struts2是从WebWork框架上发展起来的。WebWork是一个很优秀的MVC框架,然而,由于是一个新的框架,在一段时间内并没有被广泛应用。后来,Struts和WebWork社区决定将二者合并,推出Struts2框架。Struts2兼具Struts1和WebWork的优点,从而得到了广泛的使用。
为了尽快对Struts2框架有较为全面的了解,本节首先介绍Struts2的工作原理。Struts2工作原理比较复杂,图1-1-1是官方提供的Struts2工作原理图。
下面结合图1-1-1展示的Struts2工作原理,对Struts2的基本工作过程进行总结:
图1-1-1 Struts2工作原理
(1)客户端向服务器端提交请求,容器初始化HttpServletRequest请求对象。
(2)请求对象被一系列的Servlet过滤器过滤。Struts2中的过滤器有三种,如下所述:
① ActionContextCleanUp过滤器:是一个可选的过滤器,主要用来集成其他框架。
② 其他插件的核心过滤器:如SiteMesh插件的过滤器。
③ FilterDispatcher过滤器:是Struts2 API中提供的过滤器,必须使用。
(3)FilterDispatcher过滤器调用ActionMapper,决定该请求是否需要调用某个Action。
(4)如果请求需要调用某个Action,ActionMapper将通知FilterDispatcher过滤器把请求的处理交给ActionProxy来处理。
(5)ActionProxy通过Configuration Manager解析框架的配置文件struts.xml,找到需要调用的Action类。
(6)ActionProxy将创建一个ActionInvocation实例。
(7)ActionInvocation实例使用命令模式回调Action中的execute方法,Action调用业务逻辑类完成业务逻辑。在调用Action的前后,将调用该Action涉及的相关拦截器(Interceptor)。
(8)Action执行完毕后,ActionInvocation根据struts.xml中的配置找到对应的返回结果(称为Result)。返回结果通常是JSP、FreeMarker等模板文件。
在阐述Struts2工作原理的过程中,涌现了很多新名词,如拦截器、返回结果等,读者暂时不需要深入考虑,在后续章节将继续详细学习。
为了帮助读者快速入门Struts2开发,下面总结Struts2应用开发过程中开发人员需要做的主要工作。
(1)Model层开发。
Struts2框架对于Model层没有特别要求,也没有特殊支持,Model层可以使用任何开发技术实现,如JavaSE的普通Java类(POJO)、EJB组件、WebService等。Model层的业务逻辑往往使用Action类调用。
(2)在web.xml中配置FilterDispatcher。
FilterDispatcher是Struts2中的核心控制器,在Struts2 API中已经定义。在Struts2应用中,必须通过web.xml配置FilterDispatcher过滤器,代码如下所示:
<filter> <filter-name>FilterDispatcher</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>FilterDispatcher</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
上述配置中将FilterDispatcher映射到/*路径,那么客户端对服务器端的任何路径的请求,都将被FilterDispatcher过滤。
(3)开发Action类。
Action类是一个符合一定命名规范的JavaSE类,不是Servlet。Action实现的功能与Servlet类似,承担调用Model、根据返回结果决定页面导航等职责。在Struts2应用中,需要编写大量的Action类,作为业务控制器使用。
(4)拦截器(Interceptor)的配置或自定义开发。
拦截器用来在Action类的前后执行一些通用的操作,Struts2 API中已提供了常用的拦截器,只需要进行配置即可使用。如果应用中需要自定义一些通用操作,需要自定义拦截器,并通过配置使用。
(5)开发视图。
Struts2可以支持多种视图技术,包括JSP、FreeMarker、Velocity。目前,使用较多的仍然是JSP技术,本教材中也采用JSP技术实现视图。Struts2框架提供了强大的JSP标记库,可以便捷地开发JSP页面。
1.2 Struts2简单实例
通过上一节的学习,读者已经了解Struts2基本概念以及工作原理,并且对Struts2应用开发中的主要工作也有所了解。本节将构建简单的Struts2实例,该实例实现如下逻辑:用户在index.jsp中输入用户名和密码,如果用户名和密码是ETC和123,则登录成功,显示欢迎页面welcome.jsp;否则,登录失败,跳转到index.jsp页面。该实例不注重业务逻辑,主要目的是帮助读者快速掌握开发Struts2应用的步骤。
(1)到Struts官方网站下载Struts的jar包(http://struts.apache.org/)。
(2)将下载到的jar包导入到Web工程中。
Struts2框架有很多jar包,某些包是和其他插件有关的。如果将全部jar包都导入到工程中,需要同时导入其他插件的jar包,否则将出现错误。如果不需要使用其他插件,仅导入下面5个jar包即可实现Struts2的基本功能,如图1-1-2所示。
图1-1-2 导入Struts2的5个核心包
(3)开发Model层业务逻辑。
导入所需要的jar包后,下面使用Java类实现Model层的登录逻辑,代码如下所示:
public class LoginService{ public boolean login(String custname,String pwd){ if(custname.equals("ETC")&&pwd.equals("123")){ return true; }else{ return false; }}}
(4)开发视图文件。
完成业务逻辑后,进一步可以开发视图文件,视图使用JSP实现。JSP文件中可以使用Struts2框架提供的JSP标记库,使用Struts2的标记与使用JSTL的标记步骤相同。Struts2标记库只有一个tld文件,存在于struts2-core.jar包的META-INF目录下,如图1-1-3所示。
图1-1-3 struts-tags.tld文件所在目录
首先编写index.jsp文件,用来输入用户名和密码进行登录,代码如下所示:
<body> <%@taglib uri="/struts-tags" prefix="s" %> <s:form action=""> Input your custname:<s:textfield name="custname"></s:textfield><br> Input your password:<<s:password name="pwd"></s:password><br> <s:submit value="Login"></s:submit> </s:form> </body>
上述代码中使用了Struts2框架的标记库来构建表单,如<s:textfield>表示文本框,<s:password>表示密码框。
接下来编写welcome.jsp文件,当登录成功后,显示欢迎信息,代码如下所示:
<body> Welcome,${param.custname} </body>
欢迎页面将显示登录的用户名,使用EL显示请求参数custname的值。
(5)定义Action类,调用业务逻辑,返回结果视图。
业务逻辑和视图都完成后,需要创建控制器,将二者联系起来,Action是Struts2使用的业务控制器。Action类不需要继承或实现任何父类或接口,只要遵守某些命名规范即可:如果该Action类是通过表单提交调用,且Action类中需要使用表单提交的请求参数,那么必须在Action类中声明与表单域的名字对应的变量,并为变量提供getters/setters方法;Action类中必须有一个public String execute(){}形式的方法,该方法将在访问Action时被Struts2框架自动调用,实现控制逻辑。
下面创建LoginAction类,调用Model中的登录逻辑,并根据登录结果不同而返回不同的结果,代码如下所示:
public class LoginAction{ private String custname; private String pwd; public String getCustname(){ return custname; } public void setCustname(String custname){ this.custname=custname; } public String getPwd(){ return pwd; } public void setPwd(String pwd){ this.pwd=pwd; } public String execute(){ LoginService ls=new LoginService(); boolean flag=ls.login(custname,pwd); if(flag){ return"success"; }else{ return"fail"; }}}
可见,由于LoginAction类通过index.jsp中的表单提交请求,且LoginAction类中需要使用登录表单的请求参数值,所以LoginAction类中声明了与index.jsp中表单元素对应的属性custname和pwd,并提供了getters和setters方法。在LoginAction类的execute方法中,可以直接使用请求参数custname和pwd,不需要像Servlet中那样使用request.getParameter方法获取。请求参数的赋值过程将在后面章节学习。execute方法通过调用LoginService类中的login方法进行登录验证,登录成功返回success字符串,否则返回fail字符串。
(6)在struts.xml中配置Action类。
前面的步骤已经创建了Action类LoginAction,但必须在struts.xml中进行配置才能使用。在Web工程的src文件夹下,创建struts.xml文件,如图1-1-4所示。
图1-1-4 在src目录下创建struts.xml文件
框架在加载自定义的struts.xml文件前,会先加载框架自带的配置文件struts-default.xml,所以首先了解一下struts-default.xml文件。struts-default.xml文件存在于struts2-core.jar包中,定义了Struts2的基本配置信息,定义了名字为struts-default的包。struts-defualt.xml的部分配置信息如下:
<package name="struts-default" abstract="true"> <result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher"class="org.apache.struts2.dispatcher.ServletDispatcherResult"default= "true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker. FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher. HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher. ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher. StreamResult"/> <result-type name="velocity" class="org.apache …
struts.xml文件规范与struts-default.xml相同,可以根据struts-default.xml来修改struts.xml。struts.xml的基本结构如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> </struts>
struts.xml中的所有元素都必须在<struts></struts>标记之间。Action必须在<package>元素中配置,使用<action>元素配置,主要指定name属性和class属性。name属性可以是任意合法标记符,调用Action即通过name值调用;class属性指定Action的完整类名。代码如下所示:
<struts> <package name="com.etc.chapter01"extends="struts-default"> <action name="Login"class="com.etc.LoginAction"> <result name="success">/welcome.jsp</result> <result name="fail">/index.jsp</result> </action> </package> </struts>
上述配置文件将LoginAction类定义成一个名字为Login的Action,该Action存在于com.etc.chapter01包中,同时为Action定义了两个返回结果result,分别是success和fail,对应页面分别为welcome.jsp和index.jsp。Action的配置信息必须放在<package>元素中,每个<package>必须使用name属性指定包名,同时必须通过extends属性指定该包继承的父包。某个包继承了父包之后,该包就具有父包中定义的对象。默认情况下,自定义的包都应该继承struts-default.xml中的struts-default包,因为struts-defautl.xml中的struts-default包定义了很多必要的对象。
<action>元素的子元素通常是<result>,<result>的name属性与Action类的execute方法的返回值对应,例如,LoginAction类的execute方法有success和fail两个返回值,代码如下所示:
if(flag){ return"success"; }else{ return"fail"; }
由于LoginAction中的execute方法有两个可能的返回值,即success和fail,所以需要配置两个<result>,<result>的name属性值分别是success和fail,对应execute方法返回不同值时的页面导航。通过在struts.xml中配置LoginAction,定义了如下信息:
① 使用LoginAction时,通过Action的name值访问,即Login。
② 容器根据LoginAction的execute方法返回值来匹配<result>的name属性,决定页面导航。如返回success时,跳转到welcome.jsp页面;返回fail时,跳转到index.jsp页面。
(7)在index.jsp中调用LoginAction。
开发并配置LoginAction后,就可以在JSP中调用LoginAction,代码如下所示:
<body> <%@taglib uri="/struts-tags" prefix="s" %> <s:form action="Login"> <s:textfield name="custname" label="Input your custname"></s:textfield> <s:password name="pwd" label="Input your password"></s:password> <s:submit value="Login"></s:submit> </s:form> </body>
上述代码中,将表单的action属性值指定为LoginAction的名字Login,如<s:form action="Login">,从而,表单将被提交到LoginAction。
(8)在web.xml中配置FilterDispatcher。
如上节中演示的Struts2工作原理图,任何一个客户端的请求都必须经过FilterDispatcher进行过滤,才能进入Struts2架构流程。FilterDispatcher是Struts2框架API中提供的类,必须在web.xml中将其配置给任意URL才能生效。代码如下所示:
<filter> <filter-name>FilterDispatcher</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>FilterDispatcher</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
至此,简单的Struts2实例已经开发完成,部署到容器中后,访问index.jsp页面,输入用户名和密码进行登录,如图1-1-5所示。
图1-1-5 index.jsp页面
在index.jsp页面中输入用户名ETC和123 后,单击“Login”按钮,将请求提交到LoginAction,LoginAction将调用LoginService中的login方法,登录成功,跳转到welcome.jsp欢迎页面,如图1-1-6所示。
图1-1-6 欢迎页面
如果输入其他用户名和密码,则登录失败,跳转到index.jsp页面,并回显曾经输入的用户名,如图1-1-7所示。
图1-1-7 登录失败
可见,登录失败跳转到index.jsp时,用户名自动回显,不用写任何脚本。因为index.jsp中的表单不是使用HTML标记完成,而是使用Struts2的标记完成的,标记已经实现了回显的功能。
1.3 实例的运行过程
本节将结合Struts2的工作原理,了解上节中实例的运行过程,帮助读者更进一步理解Struts2框架。实例的大致运行过程如下:
访问http://localhost:8080/chapter01/index.jsp页面,如图1-1-8所示。
图1-1-8 登录页面
index.jsp页面中的表单使用Struts2框架的JSP标记构建,容器对JSP页面进行解析,将最终结果输出到客户端浏览器。在页面中单击右键,查看源代码,如下所示:
<form id="Login" name="Login" onsubmit="return true;" action="/chapter01/Login.action " method="post"><table class="wwFormTable"> <tr> <td class="tdLabel"><label for="Login_custname" class="label">Input your custname:</label> </td> <td><input type="text" name="custname" value="" id="Login_custname"/></td> </tr> <tr> <td class="tdLabel"><label for="Login_pwd" class="label">Input your password: </label> </td> <td><input type="password" name="pwd" id="Login_pwd"/></td> </tr> <tr> <td colspan="2"><div align="right"><input type="submit" id="Login_0" value= "Login"/> </div></td> </tr> </table></form>
分析上面的源码可见,容器执行index.jsp后,输出到客户端的是解析后的HTML代码,其中表单的action值被解析为action="/chapter01/Login.action"。默认情况下,容器总是将Action路径解析成后缀为.action的URL。
用户输入用户名和密码,单击“Login”按钮后,则向服务器端发送请求,请求的URL根据表单的action值生成http://localhost:8080/chapter01/Login.action。
web.xml中对/*的URL配置了过滤器FilterDispatcher,所以该请求将被FilterDispatcher过滤。
FilterDispatcher调用ActionMapper,ActionMapper判断URL的资源后缀为.action,因此ActionMapper认为需要调用Struts2框架中的Action类。
FilterDispatcher将请求处理交给ActionProxy,ActionProxy通过解析URL,认为需要调用的Action的名字是Login。
ActionProxy通过Configuration Manager解析struts.xml,找到name=Login的Action配置。
ActionProxy实例化ActionInvocation类。ActionInvocation实例调用与Action有关的拦截器以及Action类的execute方法。其中拦截器的内容将在后面章节学习。每一个Action都默认存在很多拦截器,其中有一个拦截器的功能就是将提交表单的请求参数赋值给Action的实例变量。如index.jsp中表单的custname和pwd域的值,将被赋值给LoginAction中的custname和pwd变量。
Action执行结束后,根据struts.xml中配置的action的result,将页面导航到URL。
到此为止,已经通过详细步骤解析了上节实例的运行过程。通过学习这个实例的运行步骤,可以更为清楚地理解Struts2的工作原理。
1.4 Struts2的特点
上节使用Struts2框架完成了一个简单实例,展示了Struts2应用开发的基本步骤。本节将与Servlet/JSP开发技术进行对比,总结Struts2框架的特点。
(1)Model层无区别。
使用Struts2框架开发Web应用时,Model层的开发没有特殊要求,可以使用普通的JavaSE类、EJB组件或者其他技术实现。
(2)Controller层区别最大。
MVC框架中最强大的部分往往都是Controller层。使用Servlet和JSP开发Web应用,往往使用Servlet承担Controller层。而使用Struts2开发Web应用,Controller层包含三部分:过滤器、拦截器、Action。其中Action是数量最多的控制器,基本可以替代Servlet的功能。
(3)单元测试。
Servlet无法脱离容器环境进行单元测试,因为Servlet的doXXX方法的参数是请求和响应,而请求和响应对象依赖容器创建,所以Servlet无法脱离容器环境进行单元测试。而Struts2中的控制器Action的execute方法没有参数,所以可以脱离容器环境进行单元测试。
(4)获取请求参数。
Servlet中获取表单的请求参数,需要使用request.getParameter方法实现。Action中按照命名规范声明与表单元素对应的属性以及getter/setter方法,拦截器可以自动拦截请求参数,封装到Action对应的属性中,在execute中可以直接使用。
(5)页面导航。
Servlet中的页面导航在doXXX方法中通过sendRedirect或者forward方法进行,导航页面的URL硬编码到Servlet源代码中。Action中的页面导航在struts.xml中通过result定义,页面URL不需要硬编码到源码中,可维护性增强。
(6)视图技术。
Servlet中直接支持的视图技术只有JSP一种,而Struts2可以支持多种视图技术,包括JSP、FreeMarker、Velocity。
(7)JSP标记库。
Struts2提供了强大的JSP标记库,能够实现很多动态功能,如输入信息回填、校验信息显示等,同时也可以使用JSTL等其他标记库。
Struts2还有很多优点,例如可配置的输入校验、便捷的国际化编程等。本节只列出现阶段能够理解的优点,其他相关内容会在后面章节学习。
1.5 教材案例准备
为了帮助读者更轻松、更容易地理解相关技术,教材中使用一个案例贯穿每个知识点(案例的业务逻辑与丛书之一《JavaEE架构与程序设计》中案例相同),如果阅读过《JavaEE架构与程序设计》教材,本节可以跳过。该案例不注重业务逻辑,重点在于辅助理解每个知识点。本节将对案例进行简单介绍,并实现案例的Model部分。在后面章节中,将对案例逐渐完善,为学习各知识点起到辅助作用。
案例中的主要用例描述如下:
用例一:用户输入用户名和密码进行登录。
用例二:用户输入用户名、密码、年龄、地址进行注册,用户名不能重复。
用例三:用户登录成功后,通过欢迎页面上的超级链接,可以查看个人信息,可以查看所有注册用户的除密码外的信息。
数据库使用MySQL,创建关系表customer,如图1-1-9所示。
图1-1-9 创建customer表
本节将实现教材案例的Model部分,Model由三部分组成,下面逐一进行介绍。
(1)VO类。
VO(Value Object)即值对象,用来封装实体数据,在MVC各层之间传递数据。“教材案例”中只有一种实体,即客户,所以需要创建一个Customer类,作为VO类使用。代码如下所示:
package com.etc.vo; public class Customer{ private String custname; private String pwd; private Integer age; private String address; public Customer(){ super(); } public Customer(String custname,String pwd){ super(); this.custname=custname; this.pwd=pwd; } public Customer(String custname,String pwd,Integer age,String address){ super(); this.custname=custname; this.pwd=pwd; this.age=age; this.address=address; } public String getCustname(){ return custname; } public void setCustname(String custname){ this.custname=custname; } public String getPwd(){ return pwd; } public void setPwd(String pwd){ this.pwd=pwd; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age=age; } public String getAddress(){ return address; } public void setAddress(String address){ this.address=address;}}
VO类中封装了客户的4个属性,包括custname、pwd、age以及address,同时为这些属性提供了getter和setter方法,用来返回及设置属性。
(2)DAO层。
DAO(Data Access Object)即数据访问对象,用来封装数据访问逻辑。很多时候,初学者可能将数据访问逻辑与业务逻辑混在一起实现。然而,很多数据访问逻辑可能被多个业务逻辑共同使用,如银行系统中的存款和取款两个业务逻辑,都会使用到修改余额的数据访问逻辑。因此,有必要将数据访问逻辑与业务逻辑分离。通过分析教材案例的业务逻辑,可以总结出案例中需要实现根据用户名查询、根据用户名密码查询、插入一条记录、查询所有记录四种数据逻辑,那么将这4种数据逻辑使用接口CustomerDAO定义,在类CustomerDAOImpl中实现,作为数据访问对象使用。
由于数据访问逻辑中总需要获得连接对象,所以将获得连接对象的方法封装到一个工具类中。创建工具类JDBCConnectionFactory,作为Connection对象的工具类,代码如下所示:
public class JDBCConnectionFactory{ public static Connection getConnection(){ Connection conn=null; try{ Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/scwcd","root","123 "); }catch(ClassNotFoundException e){ e.printStackTrace(); }catch(SQLException e){ e.printStackTrace(); } return conn; }}
上述代码中声明了一个静态方法getConnection,可以获得一个MySQL数据库的连接对象。接下来,创建CustomerDAOImpl类,实现4个数据逻辑方法。代码如下所示:
public class CustomerDAOImpl implements CustomerDAO{ public List<Customer>selectAll(){ List<Customer>list=new ArrayList<Customer>(); Connection conn=JDBCConnectionFactory.getConnection(); try{ Statement stmt=conn.createStatement(); String sql="select custname,age,address from customer"; ResultSet rs=stmt.executeQuery(sql); while(rs.next()){ list.add(new Customer(rs.getString(1),null,rs.getInt(2),rs.getString(3))); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return list; } public Customer selectByName(String custname){ Customer cust=null; Connection conn=JDBCConnectionFactory.getConnection(); String sql="select*from customer where custname=?"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,custname); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ cust=new Customer(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getString(4)); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return cust; } public Customer selectByNamePwd(String custname,String pwd){ Customer cust=null; Connection conn=JDBCConnectionFactory.getConnection(); String sql="select*from customer where custname=?and pwd=?"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,custname); pstmt.setString(2,pwd); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ cust=new Customer(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getString(4)); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return cust; } public void insert(Customer cust){ Connection conn=JDBCConnectionFactory.getConnection(); String sql="insert into customer values(?,?,?,?)"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,cust.getCustname()); pstmt.setString(2,cust.getPwd()); pstmt.setInt(3,cust.getAge()); pstmt.setString(4,cust.getAddress()); pstmt.executeUpdate(); }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace();}}}}}
上述代码中,CustomerDAOImpl类通过JDBCConnectionFactory获得数据库连接对象,然后使用JDBC API进行数据库编程,实现了4个数据访问逻辑。
(3)Service层。
实现了必需的数据逻辑后,就可以实现业务逻辑,往往使用服务类来封装业务逻辑,案例中创建CustomerService接口,定义登录、注册、查看个人信息、查看所有人信息4种业务逻辑。在CustomerServiceImpl类中使用DAO层数据访问逻辑,实现业务逻辑。代码如下所示:
public class CustomerServiceImpl implements CustomerService{ private CustomerDAO dao; public void setDao(CustomerDAO dao){ this.dao=dao; } public boolean login(String custname,String pwd){ Customer cust=dao.selectByNamePwd(custname,pwd); if(cust!=null){ return true; }else{ return false; } } public boolean register(Customer cust){ Customer c=dao.selectByName(cust.getCustname()); if(c==null){ dao.insert(cust); return true; }else{ return false; } } public Customer viewPersonal(String custname){ return dao.selectByName(custname); } public List<Customer>viewAll(){ return dao.selectAll(); }
至此,案例中的Model部分已经完成,共分为三部分,分别为VO、DAO、Service,在Service层最终实现了所有业务逻辑,控制器将调用Service层的业务逻辑实现功能。
1.6 本章小结
本章主要目标是帮助读者快速入门Struts2框架。Struts框架已经盛行多年,然而Struts2和Struts1之间并不是扩展和升级关系。Struts2是另一个著名框架WebWork的扩展,与Struts1没有太多直接的联系。本章首先结合官方网站的Struts2工作原理图,介绍Struts2的基本工作流程。接下来,通过一个简单实例展示Struts2应用的开发步骤,帮助读者能够顺利开发、部署并运行基于Struts2框架的Web应用。同时,结合该简单实例进一步解释了Struts2运行过程,以帮助读者直观理解Struts2的工作原理。本章还为教材接下来的章节准备了一个实例,称为“教材案例”,将在后面章节中不断完善,以辅助学习相关知识点。