JavaEE第三次实验

实验三 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 处理结束后,将调用哪种视图资源来呈现处理结果。

(三)实验内容及步骤

  1. 新建Web 工程struts-prj2,并将Struts2 中的8 个核心包添加到工程中;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LVm8lhPs-1634041997832)(C:\Users\YIYI\AppData\Roaming\Typora\typora-user-images\image-20211011102024180.png)]

  2. 在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>
    
  3. 在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>
    
  4. 在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;
        }
    }
    
  5. 在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;
        }
    }
    
  6. 在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";
        }
    }
    
    
  7. 在工程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>
    
  8. 编辑Web的web.xml文件,增加Struts2核心Filter的配置;

  9. 配置struts-prj2部署在Tomcat服务器上,访问login.jsp和register.jsp页面,并记录运行结果;

    image-20211011110921376

    image-20211011110939348

  10. 动态方法调用方式(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>
    
  11. 提交按钮方式

    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>
    
  12. 通配符方式

    #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>
    
  13. 修改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";
        }
    }
    

    image-20211011204556477

  14. 修改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>
    

    image-20211011205415428

(四)实验总结

  • 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流

  • image-20211011211331079

二、提高实验——ActionSupport与输入校验

(一)实验目的

  1. 了解Action 接口的作用,理解ActionSupport 类的作用;
  2. 掌握在Struts2 中使用校验器或手工编码的方式,对请求参数进行数据校验的方法,掌握在JSP 页面中显示错误信息和提示信息的方法;
  3. 掌握在Action 中使用国际化资源文件的方法;
  4. 掌握Struts2 内置类型转换器的作用和使用方法。

(二)基本知识和原理

  1. 为了让用户开发的Action 类更规范,Struts2 提供了一个Action 接口,该接口定义了Struts2 的Action 处理类应该实现的规范;

  2. Struts2 还为Action 接口提供了一个实现类:ActionSupport,该类提供了若干默认方法,包括:默认的处理用户请求的方法(excute()方法)、数据校验的方法、添加校验错误信息的方法、获取国际化信息的方法等,部分重要方法列表如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IoQQSwNh-1634041997841)(https://i.loli.net/2021/10/11/dxioaNFUXDKhfgP.png)]

  3. Struts2 框架提供了校验器和手工编码两种方式对请求参数进行数据校验,当Action 类继承了ActionSupport 类,就可以通过定义名为“--validation.xml”的校验规则文件的方法进行校验器校验,也可以通过重写ActionSupport 类的validate()方法或validateXxx()方法进行手动校验;

  4. 在JSP 页面中使用Struts2 标签生成的表单,能将域级别的错误信息将自动显示到表单元素处;

  5. 在JSP 页面中使用fielderror 标签,可以集中显示所有的域级错误信息;使用actionerror 标签,可以显示所有的Action 级别错误信息;使用actionmessage标签,可以显示Action 消息;

  6. Struts2 框架中提供了部分内置的类型转换器,可以将请求参数的String 类型转换成基本数据类型及对应的包装器类型、日期类型、数组类型、集合类型等,当Action 类继承了ActionSupport 类,则内置的类型转换器将默认生效,可以直接使用;

  7. 如需修改默认的类型转换校验信息,则要在Action 类的包中声明名为“Action类名.properties”的局部属性文件;

  8. Struts2 框架同时支持自定义类型转换器,将请求参数转换成任意一种类型。

(三)实验内容及步骤

  1. 修改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", "请输入您的密码! ");
            }
        }
    
  2. 修改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>
    

    image-20211011224230910

  3. 修改login.jsp页面,在表单钱增加fielderror标签,再通过浏览器访问

    image-20211011224410410

  4. 修改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";
            }
        }
    
  5. 修改login.jsp页面增加actionerror标签;修改loginSuccess.jsp,使用actionmessage标签显示Action提示消息

  6. 修改sruts.xml文件中用户登录页面导航设置,将登录失败时转向的页面从loginFail.jsp转为login.jsp

    image-20211011225311806

    image-20211011225329324

  7. 创建"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>
    

    image-20211012001211163

  8. 将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=登录成功
    
  9. 创建struts.properties文件,加载资源文件

    struts.custom.i18n.resources=cn.edu.zjut.local.message
    struts.i18n.encoding=GBK
    
  10. 修改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"));
            }
        }
    
  11. 修改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>
    
  12. 运行结果

    image-20211012002205851

  13. 修改UserBean.java,将用于保存注册用户生日的变量类型该类Date类型,使用Struts2内置的类型转换器对请求参数进行校验

    image-20211012002700153

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ULsVxrTL-1634041997851)(https://i.loli.net/2021/10/12/VcwTdlPWEpg4sIB.png)]

  14. 创建局部属性文件“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>
    

    image-20211012005325364

  15. 创建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>
    

    image-20211012011059456

  16. 修改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"));
            }
        }
    

    image-20211012012012534

(四)实验总结

  • 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

(一)实验目的

  1. 掌握在Action 中访问Servlet API 的四种方法,理解四种方法的区别;
  2. 进一步理解Action 与Servlet 的区别;
  3. 进一步熟悉Struts2 标签的使用方法;

(二)基本知识与原理

  1. Struts2 框架中的Action 类没有与任何Servlet API 耦合,因此Action 类可以脱离Servlet 容器环境进行单元测试;
  2. ActionContext 是com.opensymphony.xwork2 包中的一个类,该类表示一个Action 运行时的上下文;
  3. 当Action 类需要通过请求、会话或上下文存取属性时,可以通过ActionContext类完成,也可以通过实现Struts 提供的接口:RequestAware、SessionAware和ApplicationAware 完成,而不必调用Servlet API 中的HttpServletRequest、HttpSession 和ServletContext 对象,从而保持Action 与Servlet API 的解耦;
  4. 在Action 类中直接访问Servlet API,可以通过实现Struts2 提供的接口:ServletContextAware、ServletRequestAware、ServletResponseAware 完成,也可以通过ServletActionContext 工具类实现,但Action 将与Servlet API 直接耦合。

(三)实验内容及步骤

  1. 修改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";
            }
        }
    
  2. 修改loginSuccess.jsp页面,从请求、会话和上下文对象中获取属性值并显示

    本站访问次数为:<s:property value="#application.counter"/>
    <s:property value="#session.user"/>
    <s:property value="#request.tip"/>
    

    image-20211012164551718

  3. 修改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";
            }
        }
    }
    

    image-20211012165533481

  4. 修改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";
            }
        }
    

    image-20211012173504386

  5. 修改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";
            }
        }
    

    image-20211012183306012

  6. 利用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;
        }
    }
    
  7. 在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;
        }
    }
    
  8. 在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) {}
    }
    
  9. 修改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";
            }
    
  10. 修改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>
    
    

    image-20211012195508924

(四)实验总结

  1. ActionContext方式先通过获取的ActionContext对象,再通过get、getSession、getAppliaction方法获取相应的map对象;
  2. RequestAware, SessionAware, ApplicationAware接口方式通过设置setter方法获取request、session和application;
  3. ServletContextAware、ServletRequestAware、ServletResponseAware方法同样需要通过setter方法获取request、session和application;
  4. ServletActionContext工具类方法通过ServletActionContext对象的get方法获取相应对象;
  5. 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)]

(四)实验总结

  1. ActionContext方式先通过获取的ActionContext对象,再通过get、getSession、getAppliaction方法获取相应的map对象;
  2. RequestAware, SessionAware, ApplicationAware接口方式通过设置setter方法获取request、session和application;
  3. ServletContextAware、ServletRequestAware、ServletResponseAware方法同样需要通过setter方法获取request、session和application;
  4. ServletActionContext工具类方法通过ServletActionContext对象的get方法获取相应对象;
  5. 1和2是Map类型,3和4是HttpServletRequest、HttpServletResponse和ServletContext类型的;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yiyiqwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值