实验三 Struts的控制器组件Action——登录用户的功能扩展
一、基础实验——Action的自定义方法
(一)实验目的
1、掌握Struts2 的Action 类中自定义方法的使用;
2、掌握Struts2 中Action 类的不同调用方式和相应的配置方法;
3、掌握Action 的实例化情况,理解Action 与Servlet 在实例化上的区别;
4、理解JSP 文件中获取Action 属性的过程;
5、了解Struts2 支持的Action 处理结束后的结果类型。
(二)基本知识和原理
1、Action 类中的默认方法名是execute()方法,可以被自动调用;
2、在Action 中也允许定义其它方法名,可以同时定义多个方法,分别处理不同的逻辑;
3、当Action 中使用了自定义方法,则该Action 就需要特定的配置,一般有四种调用方式:
(1)在struts.xml 文件中通过method 属性指定方法名;
(2)使用动态方法调用方式(DMI);
(3)使用提交按钮的method 属性;
(4)使用通配符配置Action;
4、Action 类是多实例的,Action 类的属性是线程安全的;
5、在JSP 页面中,可以通过Struts2 标签调用Action 中对应的getter 方法,从而输出Action 的属性值;
6、当一个Action 处理用户请求结束后,返回一个字符串作为逻辑视图名,再通过struts.xml 文件中的配置将逻辑视图名与物理视图资源关联起来;Struts2默认提供了一系列的结果类型(struts-default.xml 配置文件的result-types 标签里列出了所支持的结果类型),结果类型决定了Action 处理结束后,将调用哪种视图资源来呈现处理结果。
(三)实验内容及步骤
-
新建Web 工程struts-prj2,并将Struts2 中的8 个核心包添加到工程中;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LVm8lhPs-1634041997832)(C:\Users\YIYI\AppData\Roaming\Typora\typora-user-images\image-20211011102024180.png)]
-
在struts-prj2中新建login.jsp页面,作为用户登录的视图;新建loginFail.jsp页面,作为登录失败的视图;新建loginSucess.jsp视图,作为登录成功的视图;
#login.jsp <%@ 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" key="login.account.lable"/> <s:password name="loginUser.password" key="login.password.lable"/> <s:submit name="submit" key="login.submit.button"/> </s:form> </body> </html>
#loginFail.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登陆失败</title> </head> <body> 登陆失败 </body> </html>
#loginSuccess.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录成功</title> </head> <body> 登录成功 </body> </html>
-
在struts-prj2中新建register.jsp页面,作为用户注册的视图;新建regFail.jsp页面,作为注册失败的视图;新建regSuccess.jsp页面,作为注册成功的视图;
#register.jsp <%@ 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" key="register.account.lable"/> <s:password name="loginUser.password" key="register.password.lable"/> <s:password name="loginUser.repassword" key="register.repassword.lable"/> <s:radio name="loginUser.sex" list="#{1:'男', 0:'女'}" key="register.sex.lable"/> <sx:datetimepicker name="loginUser.birthday" displayFormat="yyyy-MM-dd" key="register.birthday.lable"/> <s:textfield name="loginUser.address" key="register.address.lable"/> <s:textfield name="loginUser.phone" key="register.phone.lable"/> <s:textfield name="loginUser.email" key="register.email.lable"/> <s:submit name="sign up" key="register.submit.button"/> <s:reset name="reset" key="register.reset.button"/> </s:form> </body> </html>
#regFail.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注册失败</title> </head> <body> 注册失败 </body> </html>
#regSuccess.jsp <%@ 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>
-
在struts-prj2 中新建cn.edu.zjut.bean 包,并在其中创建UserBean.java,用于记录用户信息;
package cn.edu.zjut.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; } }
-
在struts-prj2 中新建cn.edu.zjut.service 包,并在其中创建UserService.java,用于实现登录逻辑和注册逻辑;
package cn.edu.zjut.service; import cn.edu.zjut.bean.UserBean; public class UserService { public boolean login(UserBean loginUser){ if(loginUser.getAccount().equals(loginUser.getPassword())){ return true; } return false; } public boolean register(UserBean registerUser){ if(registerUser.getAccount().equals(registerUser.getPassword()) && registerUser.getPassword().equals(registerUser.getRepassword()) && !registerUser.getAccount().equals("")){ return true; } return false; } }
-
在struts-prj2 中新建cn.edu.zjut.action 包,并在其中创建UserAction.java,定义login()方法和register()方法,参照“实验二Struts 基础应用”写入代码,分别用于调用登录逻辑和注册逻辑;
package cn.edu.zjut.action; import cn.edu.zjut.bean.UserBean; import cn.edu.zjut.service.UserService; public class UserAction { private UserBean loginUser; public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } public String login(){ UserService userService = new UserService(); if(userService.login(loginUser)){ return "success"; } return "fail"; } public String register(){ UserService userService = new UserService(); if(userService.register(loginUser)){ return "success"; } return "fail"; } }
-
在工程struts-prj2的src目录中创建struts.xml文件,配置Action并设置页面导航,通过action标签中method属性指定方法名;
<?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> 元素用于进行包配置,在 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="cn.edu.zjut.action.UserAction" method="login"> <result name="success">/loginSuccess.jsp</result> <result name="fail">/loginFail.jsp</result> </action> <action name="register" class="cn.edu.zjut.action.UserAction" method="register"> <result name="success">/regSuccess.jsp</result> <result name="fail">/regFail.jsp</result> </action> </package> </struts>
-
编辑Web的web.xml文件,增加Struts2核心Filter的配置;
-
配置struts-prj2部署在Tomcat服务器上,访问login.jsp和register.jsp页面,并记录运行结果;
-
动态方法调用方式(DMI)
#struts.xml <action name="UserAction" class="cn.edu.zjut.action.UserAction"> <result name="loginsuccess">/loginSuccess.jsp</result> <result name="loginfail">/loginFail.jsp</result> <result name="registersuccess">/regSuccess.jsp</result> <result name="registerfail">/regFail.jsp</result> </action> #需写入以下语句不然会出现500错误 <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
#login.jsp <s:form method="post" action="UserAction!login"> <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"/> </s:form>
-
提交按钮方式
struts.xml的配置方法同DMI方式
<s:form method="post" action="UserAction"> <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" method="login"/> </s:form>
-
通配符方式
#struts.xml <action name="*Action" class="cn.edu.zjut.action.UserAction" method="{1}"> <result name="{1}sucess">/{1}Success.jsp</result> <result name="{1}fail">/{1}Fail.jsp</result> </action>
#login.jsp <s:form method="post" action="loginAction"> <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"/> </s:form>
-
修改UserAction.java,增加UserAction类的构造方法UserAction(),增加count属性,用于测试Action的实例化情况
public class UserAction { private UserBean loginUser; private Integer count=0; public UserAction(){ System.out.println("创建了一个UserAction类对象。"); } #必须要设置get方法才能被<s:property>标签获取 public Integer getCount() { return count; } public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } public String login(){ count++; UserService userService = new UserService(); if(userService.login(loginUser)){ return "loginsuccess"; } return "loginfail"; } public String register(){ UserService userService = new UserService(); if(userService.register(loginUser)){ return "registersuccess"; } return "registerfail"; } }
-
修改struts.xml文件,将UserAction的页面导航设置为redirect结果类型
<action name="login" class="cn.edu.zjut.action.UserAction" method="login"> <result name="loginsuccess" type="redirect">/loginSuccess.jsp</result> <result name="loginfail">/loginFail.jsp</result> </action>
(四)实验总结
-
Action的四种自定义方式,method方式最好理解,通过method属性表示该请求需要由哪个方法处理,DMI方式和按钮方式则通过在请求时使用!跟上方法标识来进行处理,通配符方式则通过空出的*号来代替请求中相应位置的字符,通过{num}来填充其他地方的内容。
-
通过多次访问结合控制台的信息,我们可以判断每次的请求都重新初始化了一个Action,而Servlet则会在第一次访问时创建,期间多次访问的Servlet为同一个。
-
将type改为redirect之后,发现count值不见了,默认的方式为dispatcher,重定向的方式返回jsp不带有count的值。
dispatcher主要用于返回JSP,HTML等以页面为基础View视图,这个也是Struts2默认的Result类型。
Freemarker或者Velocity是为模板准备数据;
redirect目标地址将无法通过ValueStack等Struts2的特性来获取源Action中的数据;
chain其实只是在一个action执行完毕之后,forward到另外一个action,所以他们之间是共享HttpServletRequest的;
StreamResult等价于在Servlet中直接输出Stream流
-
二、提高实验——ActionSupport与输入校验
(一)实验目的
- 了解Action 接口的作用,理解ActionSupport 类的作用;
- 掌握在Struts2 中使用校验器或手工编码的方式,对请求参数进行数据校验的方法,掌握在JSP 页面中显示错误信息和提示信息的方法;
- 掌握在Action 中使用国际化资源文件的方法;
- 掌握Struts2 内置类型转换器的作用和使用方法。
(二)基本知识和原理
-
为了让用户开发的Action 类更规范,Struts2 提供了一个Action 接口,该接口定义了Struts2 的Action 处理类应该实现的规范;
-
Struts2 还为Action 接口提供了一个实现类:ActionSupport,该类提供了若干默认方法,包括:默认的处理用户请求的方法(excute()方法)、数据校验的方法、添加校验错误信息的方法、获取国际化信息的方法等,部分重要方法列表如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IoQQSwNh-1634041997841)(https://i.loli.net/2021/10/11/dxioaNFUXDKhfgP.png)]
-
Struts2 框架提供了校验器和手工编码两种方式对请求参数进行数据校验,当Action 类继承了ActionSupport 类,就可以通过定义名为“--validation.xml”的校验规则文件的方法进行校验器校验,也可以通过重写ActionSupport 类的validate()方法或validateXxx()方法进行手动校验;
-
在JSP 页面中使用Struts2 标签生成的表单,能将域级别的错误信息将自动显示到表单元素处;
-
在JSP 页面中使用fielderror 标签,可以集中显示所有的域级错误信息;使用actionerror 标签,可以显示所有的Action 级别错误信息;使用actionmessage标签,可以显示Action 消息;
-
Struts2 框架中提供了部分内置的类型转换器,可以将请求参数的String 类型转换成基本数据类型及对应的包装器类型、日期类型、数组类型、集合类型等,当Action 类继承了ActionSupport 类,则内置的类型转换器将默认生效,可以直接使用;
-
如需修改默认的类型转换校验信息,则要在Action 类的包中声明名为“Action类名.properties”的局部属性文件;
-
Struts2 框架同时支持自定义类型转换器,将请求参数转换成任意一种类型。
(三)实验内容及步骤
-
修改UserAction类,使其继承ActionSupport类,并在UserAction类中覆盖ActionSupport类的validate()方法,用于对用户登录的请求参数account和password进行校验:若用户名或密码为空,则使用addFieldError(域级)添加错误信息;
public void validate(){ String account = loginUser.getAccount(); String pwd = loginUser.getPassword(); if(account == null || account.equals("")){ this.addFieldError("loginUser.account", "请输入您的用户名!"); } if(pwd == null || account.equals("")){ this.addFieldError("loginUser.password", "请输入您的密码! "); } }
-
修改struts.xml文件,在Action的配置中增加validate()方法校验出错时的页面导航()
<action name="login" class="cn.edu.zjut.action.UserAction" method="login"> <result name="loginsuccess">/loginSuccess.jsp</result> <result name="loginfail">/loginFail.jsp</result> <result name="input">/login.jsp</result> </action>
-
修改login.jsp页面,在表单钱增加fielderror标签,再通过浏览器访问
-
修改UserAction.java,再带哦有登录逻辑的login()方法中,对登录情况进行校验:若登录成功,使用addActionMessage()方法添加“登录成功!”的Action提示消息,若登录失败,使用addActionError()方法添加Action级别的错误信息
public String login(){ count++; UserService userService = new UserService(); if(userService.login(loginUser)){ this.addActionMessage("登录成功!"); return "loginsuccess"; } else { this.addActionError("用户名或密码错误,请重新输入!"); return "loginfail"; } }
-
修改login.jsp页面增加actionerror标签;修改loginSuccess.jsp,使用actionmessage标签显示Action提示消息
-
修改sruts.xml文件中用户登录页面导航设置,将登录失败时转向的页面从loginFail.jsp转为login.jsp
-
创建"UserAction-login-validation.xml"校验规则文件,使其与UserAction类位于同一目录下,配置校验信息,使用校验器对请求参数进行校验。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators> <field name="loginUser.account"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>用户名不能为空!!!</message> </field-validator> </field> <field name="loginUser.password"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>密码不能为空!!!</message> </field-validator> </field> </validators>
-
将login.jsp、loginSuccess.jsp、loginFail.jsp三个页面进行国际化处理,把需要进行国际化的内容以键值对形式写入资源文件message_zh_CN.properties和message_en_US.properties中
#message_en_US.properties #field error message login.account.null=Please input your account! login.password.null=Please input your password! #action error message login.error= Account or password error, please input again! #action message login.success=Login successfully! #message_zh_CN.properties #field error message login.account.null=请输入你的用户名 login.password.null=请输入你的密码! #action error message login.error=用户名或密码错误,请再次输入! #action message login.success=登录成功
-
创建struts.properties文件,加载资源文件
struts.custom.i18n.resources=cn.edu.zjut.local.message struts.i18n.encoding=GBK
-
修改UserAction.java,使用ActionSupport()类的getText()方法,获取国际化资源文件信息
public String login(){ count++; UserService userService = new UserService(); if(userService.login(loginUser)){ this.addActionMessage(this.getText("login,success")); return "loginsuccess"; } else { this.addActionError(this.getText("login.error")); return "loginfail"; } } public void validate(){ String account = loginUser.getAccount(); String pwd = loginUser.getPassword(); if(account == null || account.equals("")){ this.addFieldError("loginUser.account", this.getText("login.account.null")); } if(pwd == null || account.equals("")){ this.addFieldError("loginUser.password", this.getText("login.password.null")); } }
-
修改UserAction-login-validation.xml,获取国际化资源文件中信息
<validators> <field name="loginUser.account"> <field-validator type="requiredstring"> <param name="trim">true</param> <message key="login.account.null"></message> </field-validator> </field> <field name="loginUser.password"> <field-validator type="requiredstring"> <param name="trim">true</param> <message key="login.password.null"></message> </field-validator> </field> </validators>
-
运行结果
-
修改UserBean.java,将用于保存注册用户生日的变量类型该类Date类型,使用Struts2内置的类型转换器对请求参数进行校验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ULsVxrTL-1634041997851)(https://i.loli.net/2021/10/12/VcwTdlPWEpg4sIB.png)]
-
创建局部属性文件“UserAction.properties”,修改类型转换的校验信息,并使用native2ASCII工具将UserAction.properties重新编码
#UserAction.properties #其中invalid.fieldvalue不能随意修改, #loginUser.birthday是请求参数域名,应根据实际需要进行修改 invalid.fieldvalue.loginUser.birthday=生日必须是日期,并符合“yyyy-mm-dd”格式
<action name="register" class="cn.edu.zjut.action.UserAction" method="register"> <result name="registersuccess">/regSuccess.jsp</result> <result name="registerfail">/regFail.jsp</result> <result name="input">/register.jsp</result> </action>
-
创建UserAction-register-validation.xml文件,增加校验信息的配置,使用校验器对用户注册的请求参数进行校验,要求注册时两次密码输入相同、email地址格式符合要求等
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators> <field name="loginUser.email"> <field-validator type="email"> <param name="trim">true</param> <message>你的电子邮件必须时符合规范的</message> </field-validator> </field> <field name="loginUser.password"> <field-validator type="fieldexpression" short-circuit="true"> <param name="expression"><![CDATA[(loginUser.password == loginUser.repassword)]]></param> <message>两次密码要相同</message> </field-validator> </field> </validators>
-
修改UserAction类,将validate()的方法名改为validateLogin(),并增加validateRegister()方法
public void validateRegister(){ String email = loginUser.getEmail(); String pwd = loginUser.getPassword(); String repwd = loginUser.getRepassword(); if(!email.contains("@")){ this.addFieldError("loginUser.email", this.getText("register.email")); } if(!pwd.equals(repwd)){ this.addFieldError("loginUser.repassword", this.getText("register.repassword")); } }
(四)实验总结
-
validate()是ActionSupport类的默认方法,重写该方法可自定义校验方式,validateXxx()方法则是首字母大写,基于Xxx动态调用来对不同的请求进行数据校验。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4agpU0Bl-1634041997855)(https://i.loli.net/2021/10/12/z13a9ns6BHyUiw8.png)]
required:必填校验器
requiredstring:必填字符串校验器
int:整数校验器
double:双精度浮点数校验器
date:日期校验器
expression:表达式校验器
fieldexpression:字段表达式校验器
email:电子邮件校验器
url:网址校验器
stringlength:字符串长度校验器
regex:正则表达式校验器 -
国际化资源需要先创建资源键值对,然后struts.properties启动国际化资源,在xml文件和jsp文件中使用key属性使用,java类中使用getText()方法使用
-
内置类型转换器的使用需要创建ClassName-way-validation.xml的格式在所在Action类同目录下创建,配置validators,在配置field-validator时要选择对应的type类
三、拓展实验——Action类与ServletAPI
(一)实验目的
- 掌握在Action 中访问Servlet API 的四种方法,理解四种方法的区别;
- 进一步理解Action 与Servlet 的区别;
- 进一步熟悉Struts2 标签的使用方法;
(二)基本知识与原理
- Struts2 框架中的Action 类没有与任何Servlet API 耦合,因此Action 类可以脱离Servlet 容器环境进行单元测试;
- ActionContext 是com.opensymphony.xwork2 包中的一个类,该类表示一个Action 运行时的上下文;
- 当Action 类需要通过请求、会话或上下文存取属性时,可以通过ActionContext类完成,也可以通过实现Struts 提供的接口:RequestAware、SessionAware和ApplicationAware 完成,而不必调用Servlet API 中的HttpServletRequest、HttpSession 和ServletContext 对象,从而保持Action 与Servlet API 的解耦;
- 在Action 类中直接访问Servlet API,可以通过实现Struts2 提供的接口:ServletContextAware、ServletRequestAware、ServletResponseAware 完成,也可以通过ServletActionContext 工具类实现,但Action 将与Servlet API 直接耦合。
(三)实验内容及步骤
-
修改UserAction类,通过ActionContext获取请求、会话和上下文对象相关联的Map对象来实现存取属性的功能
//ActionContext方式获取请求、会话和上下文对象 private Map request, session, application; public String login(){ //获取ActionContext对象 ActionContext ctx = ActionContext.getContext(); //获取请求、会话和上下文相关联的Map对象 request = (Map)ctx.get("request"); session = (Map)ctx.getSession(); application = (Map)ctx.getApplication(); //访问applicationn范围的属性值 Integer counter = (Integer) application.get("counter"); if(counter == null){ counter = 1; } else{ counter += 1; } application.put("counter", counter); UserService userService = new UserService(); if(userService.login(loginUser)){ //设置session范围属性 session.put("user", loginUser.getAccount()); //设置request范围属性 request.put("tip", "您已登录成功"); return "loginsuccess"; } else{ return "loginfail"; } }
-
修改loginSuccess.jsp页面,从请求、会话和上下文对象中获取属性值并显示
本站访问次数为:<s:property value="#application.counter"/> <s:property value="#session.user"/> <s:property value="#request.tip"/>
-
修改UserAction类,通过实现Struts提供的接口:RequestAware、SessionAware和AppliactionAware,获取请求、会话和上下文对象相关联的Map对象来实现存取属性的功能
public class UserAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware { private UserBean loginUser; private Integer count=0; public UserAction(){ System.out.println("创建了一个UserAction类对象。"); } public Integer getCount() { return count; } public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } //接口方式实现 private Map request, session, application; public void setRequest(Map<String, Object> request){ this.request = request; } public void setSession(Map<String, Object> session){ this.session = session; } public void setApplication(Map<String, Object> application){ this.application = application; } public String login(){ Integer counter = (Integer) application.get("counter"); if(counter == null){ counter = 1; } else{ counter += 1; } application.put("counter", counter); UserService userService = new UserService(); if(userService.login(loginUser)){ session.put("user", loginUser.getAccount()); request.put("tip", "您已登录成功"); return "loginsuccess"; } else{ return "loginfail"; } } }
-
修改UseAction,通过接口ServletContextAware、ServletRequestAware、ServletResponseAware直接访问ServletAPI,并实现上述功能
public class UserAction extends ActionSupport implements ServletContextAware, ServletRequestAware, ServletResponseAware { private UserBean loginUser; private Integer count=0; private HttpServletRequest request; private HttpServletResponse response; private ServletContext application; public UserAction(){ System.out.println("创建了一个UserAction类对象。"); } public Integer getCount() { return count; } public UserBean getLoginUser(){ return loginUser; } public void setLoginUser(UserBean loginUser){ this.loginUser = loginUser; } //ServletContextAware、ServletRequestAware、ServletResponseAware直接访问ServletAPI public void setServletRequest(HttpServletRequest request){ this.request = request; } public void setServletContext(ServletContext application){ this.application = application; } public void setServletResponse(HttpServletResponse response) { this.response = response; } public String login(){ Integer counter = (Integer) application.getAttribute("counter"); if(counter == null){ counter = 1; } else{ counter += 1; } application.setAttribute("counter", counter); UserService userService = new UserService(); if(userService.login(loginUser)){ HttpSession session = request.getSession(); session.setAttribute("user", loginUser.getAccount()); request.setAttribute("tip", "您已登录成功"); return "loginsuccess"; } else{ return "loginfail"; } }
-
修改UserAction类,通过ServletActionContext工具类直接访问Servlet API,实现上述功能
//ServletActionContext工具类直接访问Servlet API public String login(){ HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); ServletContext application = ServletActionContext.getServletContext(); HttpSession session = request.getSession(); Integer counter = (Integer) application.getAttribute("counter"); if(counter == null){ counter = 1; } else{ counter += 1; } application.setAttribute("counter", counter); UserService userService = new UserService(); if(userService.login(loginUser)){ session.setAttribute("user", loginUser.getAccount()); request.setAttribute("tip", "您已登录成功"); return "loginsuccess"; } else{ return "loginfail"; } }
-
利用Servlet API添加购物车功能,在cn.edu.zjut.bean包中创建Item.java用于记录商品信息
package cn.edu.zjut.bean; public class Item { private String itemID; private String name; private String description; private double cost; public Item() { } public Item(String itemID, String name, String description, double cost) { this.itemID = itemID; this.name = name; this.description = description; this.cost = cost; } public String getItemID() { return itemID; } public void setItemID(String itemID) { this.itemID = itemID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public double getCost() { return cost; } public void setCost(double cost) { this.cost = cost; } }
-
在cn.edu.zjut.bean中创建ItemOrder.java用于记录购物车中的一条商品信息和购买数量
package cn.edu.zjut.bean; public class ItemOrder { private Item item; private int numItems; public ItemOrder() { } public ItemOrder(Item item){ setItem(item); setNumItems(1); } public ItemOrder(Item item, int numItems) { this.item = item; this.numItems = numItems; } public Item getItem() { return item; } public void setItem(Item item) { this.item = item; } public int getNumItems() { return numItems; } public void setNumItems(int numItems) { this.numItems = numItems; } }
-
在cn.edu.zjut.bean中常见ShoppingCart.java用于记录用户的购物车信息,为简化操作,在购物车的构造函数中加入商品信息
package cn.edu.zjut.bean; import java.util.ArrayList; import java.util.List; public class ShoppingCart { private List itemsOrdered; public ShoppingCart() { itemsOrdered = new ArrayList(); Item item = new Item("book001", "JAVAEE 技术实验指导教程", "WEB 程序设计知识回顾、" + "轻量级JAVAEE 应用框架、" + "企业级EJB 组件编程技术、" + "JAVAEE 综合应用开发.", 19.95); ItemOrder itemorder = new ItemOrder(item); itemorder.setNumItems(2); itemsOrdered.add(itemorder); } public List getItemsOrdered() { return (itemsOrdered); } public synchronized void addItem(String itemID) {} public synchronized void setNumOrdered(String itemID, int numOrdered) {} }
-
修改UserAction类的login方法,当登录成功时,创建ShoppingCart对象并存入会话中
if(userService.login(loginUser)){ session.setAttribute("user", loginUser.getAccount()); request.setAttribute("tip", "您已登录成功"); ShoppingCart shoppingCart = new ShoppingCart(); session.setAttribute("ShoppingCart", shoppingCart); return "loginsuccess"; }
-
修改loginSuccess.jsp页面,从会话中获取购物车信息并显示在页面中
<%@ taglib prefix="s" uri="/struts-tags" %> <%-- Created by IntelliJ IDEA. User: yiyi Date: 2021/10/11 Time: 20:05 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录成功</title> </head> <body> 本站访问次数为:<s:property value="#application.counter"/> <s:property value="#session.user"/> <s:property value="#request.tip"/> <br> <table border="1"> <s:iterator value="#session.shoppingcart.itemsOrdered"> <tr> <th>编号</th><th>名称</th><th>说明</th><th>单价</th><th>数量</th> </tr> <tr> <td><s:property value="item.itemID"/> </td> <td><s:property value="item.name"/> </td> <td><s:property value="item.description"/> </td> <td><s:property value="item.cost"/> </td> <td><s:property value="numItems"/> </td> </tr> </s:iterator> </table> </body> </html>
(四)实验总结
- ActionContext方式先通过获取的ActionContext对象,再通过get、getSession、getAppliaction方法获取相应的map对象;
- RequestAware, SessionAware, ApplicationAware接口方式通过设置setter方法获取request、session和application;
- ServletContextAware、ServletRequestAware、ServletResponseAware方法同样需要通过setter方法获取request、session和application;
- ServletActionContext工具类方法通过ServletActionContext对象的get方法获取相应对象;
- 1和2是Map类型,3和4是HttpServletRequest、HttpServletResponse和ServletContext类型的;
roperty value="#request.tip"/>
<s:iterator value="#session.shoppingcart.itemsOrdered">
</s:iterator>
编号 | 名称 | 说明 | 单价 | 数量 |
---|---|---|---|---|
<s:property value=“item.itemID”/> | <s:property value=“item.name”/> | <s:property value=“item.description”/> | <s:property value=“item.cost”/> | <s:property value=“numItems”/> |
```
[外链图片转存中...(img-Btei46ir-1634041997860)]
(四)实验总结
- ActionContext方式先通过获取的ActionContext对象,再通过get、getSession、getAppliaction方法获取相应的map对象;
- RequestAware, SessionAware, ApplicationAware接口方式通过设置setter方法获取request、session和application;
- ServletContextAware、ServletRequestAware、ServletResponseAware方法同样需要通过setter方法获取request、session和application;
- ServletActionContext工具类方法通过ServletActionContext对象的get方法获取相应对象;
- 1和2是Map类型,3和4是HttpServletRequest、HttpServletResponse和ServletContext类型的;