实验二 Struts基础应用——基于Struts2框架的用户登录模块
一、基础实验——Struts2框架搭建
(一)实验目的
- 掌握Struts2应用的基本开发步骤和常规配置;
- 观察表单参数与Action属性的赋值关系,观察Action的execute()方法及其返回值,并能正确应用;
- 观察配置文件struts.xml中的主要元素及属性,并能够正确应用;
- 理解Stuts2框架中MVC设计模式的体现,理解Action,FilterDispatcher,struts.xml的主要作用,并能够正确应用。
(二)基础知识与原理
-
Struts2 是从 WebWork 框架上发展起来的 MVC 框架;
-
FilterDispatcher 是 Struts2 中的核心控制器,客户端对服务器端的请求将被 FilterDispatcher 过滤;若请求需要调用某个 Action,则框架将根据配置文件 struts.xml,找到需要调用的 Action 类;
-
Action 类是一个符合一定命名规范的 JavaSE 类,作为业务控制器使用;Action 中的 execute()方法用于调用 Model 层的业务逻辑类,并根据返回结果决定页面导航;
-
若 Action 类中需要使用表单提交的请求参数,那么必须在 Action 类中声明与 表单域的名字对应的变量,并为变量提供 getters/setters 方法;
-
Action 类需要在 struts.xml 中进行配置才能使用;
-
编译运行基于 Struts2 框架的 Web 工程,需要导入 struts2 的 8 个核心 jar 包:
文件名 说明 struts2-core-2.3.15.1.jar Struts 2 框架的核心类库 xwork-core-2.3.15.1.jar XWork 类库,Struts 2 的构建基础 Ognl-3.0.6.jar Struts 2 使用的一种表达式语言类库 freemarker-2.3.19.jar Struts 2的标签模板使用类库 javassist-3.11.0.GA.jar 代码生成工具包 commons-lang3-3.1.jar Apache 语言包,是 java.lang 包的扩展 commons-io-2.0.1.jar Apache IO 包 commons-fileupload-1.3.jar Struts 2 文件上传依赖包
(三)实验内容及步骤
-
登录 http://struts.apache.org/download.cgi 站点,下载 Struts2 的最新版(Full Distribution);
-
IDEA中新建工程
-
加入Struts2相关依赖或导入jar包
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.37</version> </dependency>
-
新建login.jsp页面,作为用户登录的视图。
<form method="post" action="login"> <table> <tr> <td>用户名:</td> <td> <input name="loginUser.account" type="text"> </td> </tr> <tr> <td>密 码:</td> <td><input type="password" name="loginUser.password"></td> </tr> </table> <input type="submit" value="提交" name="提交"> </form>
-
新建loginSuccess.jsp和loginFail.jsp页面分别作为登录成功或登录失败的视图。
-
新建bean包,创建UserBean.java,用于记录登录用户信息:
package com.example.struts_prij1.bean; public class UserBean { private String account; private String password; public UserBean() { } public UserBean(String account, String password) { this.account = account; this.password = password; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
-
新建service包,并创建UserService.java,用于实现登录逻辑
package com.example.struts_prij1.service; import com.example.struts_prij1.bean.UserBean; public class UserService { public boolean login(UserBean loginUser){ if(loginUser.getAccount().equals(loginUser.getPassword())){ return true; } return false; } }
-
创建action包,并创建UserAction.java,调用登录逻辑,并根据登录结果不同而返回不同内容
package com.example.struts_prij1.action; import com.example.struts_prij1.bean.UserBean; import com.example.struts_prij1.service.UserService; public class UserAction { private UserBean loginUser; public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } public String execute(){ UserService userService = new UserService(); if(userService.login(loginUser)){ return "success"; } return "fail"; } }
-
在src目录中创建struts.xml文件,用于配置Action并设置页面导航
<?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> <package name="strutsBean" extends="struts-default"> <action name="login" class="com.example.action.UserAction"> <result name="success">/loginSuccess.jsp</result> <result name="fail">/loginFail.jsp</result> </action> </package> </struts>
-
编辑Web应用的web.xml文件,增加Struts2核心Filter配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
-
部署到Tomcat服务器
-
修改login.jsp代码
<%-- Created by IntelliJ IDEA. User: YIYI Date: 2021/9/27 Time: 10:22 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>登录</title> </head> <body> <s:form method="post" action="login.action"> <s:textfield name="loginUser.account" label="请您输入账号"/> <s:password name="loginUser.password" label="请您输入密码"/> <s:submit value="登录"/> </s:form> </body> </html>
-
运行结果
(四)实验总结
-
在修改代码之前,login.jsp的代码很显然是不正确的,需要将html标签改为Struts2的标签
<%@ taglib prefix="s" uri="/struts-tags"%>
-
由于struts 2.3版本和2.5版本发生了较大变化,一开始安装了2.5版本,struts.xml文件配置错误,出现了404错误;
-
Action属性赋值关系:
jsp中的name属性的值对应Action类中数据对象名,若数据对象的数据成员为对象则使用如下格式 例子:loginUser.name.first
Action类中execute方法的返回值为字符串,在struts.xml中为该返回值配置映射;
-
根据容器配置,服务器将请求转到FilterDispatcher进行处理,进入Struts2流程;
-
struts框架会在struts.xml配置文件中查找对应的action类,初始化该action,执行set方法,再执行execute方法;
-
框架根据execute方法返回的字符串和配置文件信息进行匹配,进而返回结果页面。
-
Action具有很好的代码复用性,无需与Servlet API耦合,同时返回的字符串作为处理结果,使得结果处理更加灵活。
<struts> <!-- <package> 元素用于进行包配置,在 Struts2 框架中,包用于组织 Action 和拦截器等信息,每个包都是由零个或多个拦截器以及 Action 所组成的集合。--> <!-- name:必填属性,用于指定该包的名称,此名称是该包被其他包引用的Key--> <!-- namespace:可选属性,用于定义包的命名空间--> <!-- extends:可选属性,用于指定该包继承自其他包,其属性值必须是另一个包的name属性值,但该属性值通常设置为struts-default,这样该包中的Action就具有了Struts框架默认的拦截器等功能--> <package name="strutsBean" extends="struts-default"> <!-- action配置指定了需要初始化哪个action类进行处理--> <!-- result则指定了对应字符串的处理结果--> <action name="login" class="com.example.action.UserAction"> <result name="success">/loginSuccess.jsp</result> <result name="fail">/loginFail.jsp</result> </action> </package> </struts>
二、提高实验——Struts2标签
(一)实验目的
- 进一步熟悉Struts2 应用的基本开发步骤和常规配置;
- 进一步熟悉Action 及配置文件struts.xml 的应用方法;
- 掌握Struts2 标签的基本使用方法;
- 能熟练使用Struts2 的常用标签,能参考Struts2 标签的使用说明文档,对各类标签进行灵活应用;
(二)基本知识与原理
- 使用Struts2 标签的形式来表达页面逻辑,可以尽量避免在视图中使用Java代码,让逻辑与显示分离,提高视图的可维护性;
- Struts2 标签库的主要tld 文件为struts-tags.tld,在struts2-core-2.3.15.1.jar 包中,另一个与Ajax 相关的标签库tld 文件为struts-dojo-tags.tld,在struts2-dojo-plugin-2.3.15.1.jar 包中;
- Struts2 标签的使用步骤和使用JSTL 相同,只需在JSP 页面中使用taglib 指令引入标签库中tld 文件的uri,并指定前缀即可,例如:<%@ taglib prefix=“s” uri="/struts-tags"%>;
- 根据Struts2 标签的主要作用,可以将其分为:用于生成页面元素的UI 标签、用于实现流程控制的控制类标签、用于控制数据的数据标签和用于支持Ajax的标签。
(三)实验内容及步骤
-
导入struts2-dojo-plugin-2.3.37.jar包到lib目录下,并加入依赖
-
新建register.jsp页面作为用户注册的视图,页面使用Struts2的UI标签来生成表单元素,包括用户名、密码、确认密码、真实姓名、性别、生日、联系地址、联系电话和电子邮箱:
<%-- Created by IntelliJ IDEA. User: yiyi Date: 2021/9/27 Time: 14:07 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags"%> <%@ taglib prefix="sx" uri="/struts-dojo-tags"%> <html> <head> <s:head theme="xhtml"/> <sx:head parseContent="true" extraLocales="UTF-8"/> </head> <body> <s:form action="register.action" method="post" onsubmit="return check()"> <s:textfield name="loginUser.account" label="请输入用户名"/> <s:password name="loginUser.password" label="请输入密码"/> <s:password name="loginUser.repassword" label="请再次输入密码"/> <s:radio name="loginUser.sex" list="#{1:'男', 0:'女'}" label="请输入性别"/> <sx:datetimepicker name="loginUser.birthday" displayFormat="yyyy-MM-dd" label="请输入生日"/> <s:textfield name="loginUser.address" label="请输入联系地址"/> <s:textfield name="loginUser.phone" label="请输入手机号"/> <s:textfield name="loginUser.email" label="请输入电子邮箱"/> <s:submit value="注册"/> <s:reset value="重置"/> </s:form> </body> </html>
-
新建regFail.jsp页面,作为注册失败的试图,显示“注册失败”
-
新建regSuccess.jsp页面,作为注册成功试图,使用Struts2的数据标签和控制标签来生成注册成功的信息,并将登录用户信息保存在会话范围内。
<%-- Created by IntelliJ IDEA. User: yiyi Date: 2021/9/27 Time: 14:37 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>注册成功</title> </head> <body> <s:property value="loginUser.name"/> <s:if test="%{loginUser.sex==\"1\"}"> <s:text name="先生, "/> </s:if> <s:else> <s:text name="女士, "/> </s:else> 您注册成功了! <s:set name="user" value="loginUser" scope="session"/> </body> </html>
-
修改UserBean类
package com.example.bean; public class UserBean { private String account=""; private String password=""; private String repassword=""; private String name=""; private String sex=""; private String birthday=""; private String address=""; private String phone=""; private String email=""; public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRepassword() { return repassword; } public void setRepassword(String repassword) { this.repassword = repassword; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
-
修改UserService.java,增加用户注册逻辑,为简化注册逻辑,健注册成功的条件设置为:用户名、密码和确认密码相同,而且不为空字符串;
public boolean register(UserBean registerUser){ if(registerUser.getAccount().equals(registerUser.getPassword()) && registerUser.getPassword().equals(registerUser.getRepassword()) && !registerUser.getAccount().equals("")){ return true; } return false; }
-
修改UserAction.java中的execute()方法,用于调用注册逻辑,并根据注册结果返回不同内容
public String execute(){ UserService userService = new UserService(); if(userService.register(loginUser)){ return "success"; } return "fail"; }
-
修改struts.xml文件,对用户注册进行配置并设置页面导航
<action name="register" class="com.example.action.UserAction"> <result name="success">/regSuccess.jsp</result> <result name="fail">/regFail.jsp</result> </action>
-
重新部署到Tomcat服务器,运行。
(四)实验总结
本次实验未出现BUG,但修改原execute的方法不是合乎常理的操作,应该要再创建一个Action来处理注册业务,而不能捡芝麻丢西瓜。
三、拓展实验——Struts2的国际化
(一)实验目的
- 进一步熟悉Struts2标签的基本使用方法;
- 能使用Struts2标签实现国际化;
- 了解配置文件struts.properties以及国际化资源文件的作用和基本使用方法。
(二)基本知识与原理
- 通过将不同语言版本的字符保存在属性文件中,Struts2的国际化机制能够在不需要修改程序主体的前提下,实现不同语言版本的应用;
- 在Web应用中选择需要进行国际化的内容,不在页面中直接输出该信息,而是通过Struts2标签输出一个键值,该键值在不同语言环境下对应不同的字符串;如::<s:textfield name=“loginUser.account” lable=“请输入用户名”/>代码中的“请输入用户名”是需要国际化的内容,将其以键值代替为<s:textfield name=“loginUser.account” key=“login.account.lable”/>;
- 需要进行国际化的内容以键值对(key=value)的形式写入Struts2的国际化资源文件中,如“login.account.lable=请输入用户名”;该资源文件名可以自定义,但后缀必须是properties;资源文件应放在Web应用的类加载路径下;每一个语言版本需要创建一个资源文件;
- 通过Struts2的配置文件struts.properties来配置资源文件的基础名,若资源文件的基础名为message,则message_zh_CN.properties是对应的中文资源文件,message_en_US.properties是对应的美国英语资源文件;
- 浏览器将根据其默认的语言版本,自动调用相应语言的资源文件,从而在页面中展示不同的语言效果。
(三)实验内容及步骤
-
在src目录下创建一个cn.edu.zjut.local包,把所有的资源文件放置其中,如:message_zh_CN.properties、message_en_US.properties等;
#message_en_US.properties login.account.lable=Please input your account login.password.lable=Please input your password login.submit.button=submit
#message_zh_CN.properties login.account.lable=请输入用户名 login.password.lable=请输入密码 login.submit.button=登录
-
对资源文件进行重新编码,避免乱码问题;
#message_zh_CN.properties login.account.lable=请输入用户名 login.password.lable=请输入密码 login.submit.button=登录
-
src目录中创建struts.properties文件,通过它加载资源文件:
struts.custom.i18n.resources=cn.edu.zjut.local.message struts.i18n.encoding=GBK
-
修改login.jsp、loginSucess.jsp和loginFail.jsp页面,通过Struts2标签实现国际化;
<!--login.jsp--> <s:textfield name="loginUser.account" key="login.account.lable"/> <s:password name="loginUser.password" key="login.password.lable"/> <s:submit name="submit" key="login.submit.button"/>
-
重新部署到Tomcat服务器
-
设置浏览器首选语言选项,访问login.jsp页面,观察并记录运行结果;
中文时访问
修改浏览器语言为英语
英文时访问
-
修改用户注册模块
#message_en_US.properties login.account.lable=Please input your account login.password.lable=Please input your password login.submit.button=submit register.account.lable=Please input your account register.password.lable=Please input your password register.repassword.lable=Please input your password again register.sex.lable=Please input your sex register.birthday.lable=Please input your birthday register.address.lable=Please input your address register.phone.lable=Please input your phone register.email.lable=Please input your email register.submit.button=Sign up register.reset.button=Reset
#message_zh_CN.properties login.account.lable=请输入用户名 login.password.lable=请输入密码 login.submit.button=登录 register.account.lable=请输入用户名 register.password.lable=请输入密码 register.repassword.lable=请再次输入密码 register.sex.lable=请输入性别 register.birthday.lable=请输入生日 register.address.lable=请输入联系地址 register.phone.lable=请输入手机号 register.email.lable=请输入电子邮箱 register.submit.button=注册 register.reset.button=重置
创建UserRegisterAction.java类处理注册业务
package com.example.action; import com.example.bean.UserBean; import com.example.service.UserService; public class UserRegisterAction { private UserBean loginUser; public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } public String execute(){ UserService userService = new UserService(); if(userService.register(loginUser)){ return "success"; } return "fail"; } }
修改struts2.xml配置
<struts> <!-- <package> 元素用于进行包配置,在 Struts2 框架中,包用于组织 Action 和拦截器等信息,每个包都是由零个或多个拦截器以及 Action 所组成的集合。--> <!-- name:必填属性,用于指定该包的名称,此名称是该包被其他包引用的Key--> <!-- namespace:可选属性,用于定义包的命名空间--> <!-- extends:可选属性,用于指定该包继承自其他包,其属性值必须是另一个包的name属性值,但该属性值通常设置为struts-default,这样该包中的Action就具有了Struts框架默认的拦截器等功能--> <package name="strutsBean" extends="struts-default"> <!-- action配置指定了需要初始化哪个action类进行处理--> <!-- result则指定了对应字符串的处理结果--> <action name="login" class="com.example.action.UserAction"> <result name="success">/loginSuccess.jsp</result> <result name="fail">/loginFail.jsp</result> </action> <action name="register" class="com.example.action.UserRegisterAction"> <result name="success">/regSuccess.jsp</result> <result name="fail">/regFail.jsp</result> </action> </package> </struts>
运行结果
(四)实验总结
通过struts2标签进行国际化能够使得一个网站多出一个properties资源文件即可完成不同语言的页面,而且各语言之间无耦合,修改非常方便。
通过本次实验,熟悉了struts2进行国际化的方式以及对struts2框架有了进一步的理解。