struts

struts2介绍
    Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新MVC框架
    核心功能
        action可以是普通类(POJO)
        一次请求对应一个action实例 (请求一次,创建一个action对象)
        struts不依赖于servlet api
        封装请求参数
        整合了OGNL(Object Graph NavigationLanguage)对象图形导航语言。比EL表达式更强大
        将值传递给视图时,使用"ValueStack"技术。--值栈
        类型转换
        数据校验
        基于Spring AOP思想的拦截器机制,更易扩展
    struts资源
        struts-2.3.14-all.zip
    struts目录结构
        apps : 应用(demo例子),例如:struts2-blank.war
        docs : 帮助文档
        lib :struts需要的所有jar
        src : 源码



helloword搭建
    1 创建web项目
    2 导入最少jar包(/struts/struts-2.3.14)
        位置:/apps/struts2-blank.war/WEB-INF/lib 所有jar
        注意:
            将war扩展名改成zip,进行解压
            不要使用 /lib 中的内容
        jar介绍
            struts2-core-2.3.14.jar     核心jar
            xwork-core-2.3.14.jar       依赖jar,使用webwork的
            ognl-3.0.6.jar              对象图导航语言
            freemarker-2.3.19.jar       struts2的ui标签模板
            commons-lang3-3.1.jar       对java.lang包的增强 
            commons-fileupload-1.2.2.jar文件上传组件
            commons-io-2.0.1.jar        文件上传依赖jar
            asm-3.3.jar                 提供了对字节码操作的功能
            asm-commons-3.3.jar         提供了基于事件的表现形式
            asm-tree-3.3.jar            提供了基于对象的表现形式
            javassist-3.11.0.GA.jar     代码生成工具,用于在运行时扩展java类
    3 编写实现类Action
        public String execute(){
            System.out.println("hello action execute 执行...");
            return "success";
        }
    4 编写核心配置文件
        名称:struts.xml
        位置:src
        内容:
            <?xml version="1.0" encoding="UTF-8" ?>
            <!DOCTYPE struts PUBLIC
                "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
                "http://struts.apache.org/dtds/struts-2.3.dtd">
            <struts>
                <package name="day01" namespace="/primer" extends="struts-default" >
                    <action name="helloAction" class="Action全限定名" method="execute">
                        <result name="success">/a_hello/demo.jsp</result>
                    </action>
                </package>
            </struts>
    5 配置struts提供的过滤器web.xml
        过滤器类名:StrutsPrepareAndExecuteFilter
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    启动服务器,访问 http://localhost:8080/项目/primer/helloAction



struts执行流程
    服务器软件启动时执行过滤器的init方法,加载struts.xml
    当每次请求时
        执行过滤器的service方法,生成Action类的代理对象,去执行拦截器,然后执行Action中的指定方法,
        并返回结果,然后生成模板(jsp),然后返回拦截器,返回过滤器,最后响应给浏览器



struts配置文件
    1 default.properties (默认设置配置文件)
        位置:struts2-core-2.3.14.jar/org/apache/struts2/default.properties
    2 struts-default.xml (stures核心配置文件)
        位置:struts2-core-2.3.14.jar/struts-default.xml
        内容:struts2编写拦截器,默认拦截器栈等
    3 struts-plugin.xml (插件配置文件)
        位置:插件jar中
    4 struts.xml (程序核心配置文件)
    5 web.xml (web配置文件,可以设置初始化参数覆盖struts默认配置)
    注意:如果多个文件配置了同一个struts2 常量,则后一个文件中配置的常量值会覆盖前面文件配置的常量值



struts常量
    struts框架用于给整个框架配置的固定key
    struts常量默认配置文件:default.properties
    用法:
        1.src/struts.xml配置
            <constant name="键" value="值"></constant>
        2.src/struts.properties,在struts.xml文件之后被加载
            键=值
        3.web.xml配置过滤器时,配置初始化参数
            <init-param>
                <param-name>键</param-name>
                <param-value>值</param-value>
            </init-param>
    常见常量
        1 struts.i18n.encoding ,用于设置编码
            例如:struts.i18n.encoding=UTF-8
        2 struts.action.extension 配置struts action的扩展名,多个扩展名之间使用,分割
            例如:struts.action.extension=action,,
                访问:http://localhost:8080/struts_day01/helloAction        没有扩展名
                访问:http://localhost:8080/struts_day01/helloAction.action 指定了扩展名
        3 struts.devMode 是否开启开发模式
            例如:struts.devMode = true 开启,默认值为false,建议开发时开启
            作用
                 struts.i18n.reload = true  ,自动加载国际化资源文件
                 struts.configuration.xml.reload = true , xml配置文件添加或修改后将自动加载
        4 struts.ui.theme struts标签的主题(布局风格)
            例如:struts.ui.theme=xhtml ,默认值。其他取值:simple 简单风格,没有任何样式
        5 struts.objectFactory 三大框架整合使用
            例如:struts.objectFactory = spring ,使用spring创建对象
        其它
            struts.serve.static.browserCache 设置浏览器是否缓存静态内容,默认为ture,开发阶段建议关闭
            struts.multipart.maxSize 上传文件的最大长度,单位字节



struts.xml
    示例
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
            "http://struts.apache.org/dtds/struts-2.3.dtd">
        <struts>
            <!-- 开启开发模式,xml配置文件将自动加载 -->
            <constant name="struts.devMode" value="true"></constant>
            <!-- 标签样式为基本样式 -->
            <constant name="struts.ui.theme" value="simple"></constant>
            <package name="defaultPackage" namespace="/" extends="struts-default">
                <action name="oneAction_*" class="action.OneAction" method="{1}">
                    <result name="success">/success.jsp</result>
                </action>
            </package>
        </struts>
    package标签
        <package> struts用于管理所有的action
            name : 给当前的包进行一个唯一的命名,用于提供给其他包继承。
            namespace : 给当前的包给一个统一访问的根路径。默认值,/
            extends : 确定需要继承的包。
                常用 : struts提供默认实现,固定值:struts-default
                    位置:struts-default.xml文件中
                    源码:<package name="struts-default" abstract="true">
        <action> : 用于配置action类
            name : 给当前类进行命名。在当前package内部不能重复。
            class : action实现类全限定类名。默认类,ActionSupport
            method : action类中执行的方法名称。默认值 execute
            访问路径:package.namespace + "/" + action.name
        <result> : 用于配置结果
            name : action方法返回值 ,默认值 success
            type :从acton到jsp方法方式。
                常用值(struts-default.xml,<package name="struts-default" abstract="true"><result-types><result-type>)
                    dispatcher,请求转发到jsp页面,默认值
                    redirect , 重定向到jsp页面 <result name="success" type="redirect">/success.jsp</result>
                    redirectAction ,重定向到指定的action
                    stream ,向浏览器发送流,如图片
                重定向到action示例
                    <result name="success" type="redirectAction">
                        <param name="namespace">/</param>
                        <param name="actionName">twoAction</param>
                    </result>
                    或
                    <result name="success" type="redirectAction">twoAction</result>
                    注意:下面的写法只能重定向到同一个namespace下的action,不加/
            <result name="input">比较特殊,可以配置错误页面,当封装数据发生错误时,返回值为input
        通配符
            星号*
                使用位置: struts.xml配置文件中,<action>的name属性中
                作用: 在其他的配置项中可以通过{n}方式获得匹配的内容,n表示星号的位置,从1开始
                例如 <action name="*_*_*"  class="" method="" 
                    访问url: http:..../part1_part2_part3 ,使用{1}获得part1内容 ; {2} part2 {3} part3
                注意:{0} 匹配整个 URI
                建议:<action name="userAction_*" method="{1}" ,访问时 userAction_add 或 userAction_delete
            感叹号!
                使用位置: 在访问action的url中
                作用: 可以用!号代替一个符号(只能是符号,且只能是一个)
                例: http://localhost:8080/client/UserAction!add
    include标签
        可以将多个struts配置文件整合到一起
            <include file=""></include>



编写action
    POJO 普通类
    可以选择 实现接口 Action
        提供5个java常量(字段)
            public static final String SUCCESS = "success"; 表示访问成功
            public static final String NONE = "none"; 没有结果集result,没有返回页面。Ajax
            public static final String ERROR = "error"; 服务器出现错误
            public static final String INPUT = "input"; 浏览器发送用户输入的数据有误
            public static final String LOGIN = "login"; 没有权限,需要登录
        默认方法
             public String execute() throws Exception;
    可以选择 继承类 ActionSupport 
        提供默认实现:验证、提示、国际化等
    方法结构
        public String 名称自定义(){return ...} ,非静态
    


action访问servlet api
    间接的访问servlet三个作用域,相当于只能执行xxxAttribute方法.
        工具类ActionContext,action的上下文(action管理者)
        api
            获得对象:ActionContext.getContext()
            放置request作用域:actionContext.put(key,value) (其实不是request作用域,而是直接添加到值栈的content中)
            放置session作用域:actionContext.getSession().put(key,value)
            放置application作用域:actionContext.getApplication().put(key,value)
    直接访问servlet api ,获得servlet对象
        工具类ServletActionContext,action中servlet的上下文
        获取servlet对象
            HttpServletRequest request = ServletActionContext.getRequest();
            HttpSession session = request.getSession();
            ServletContext application = ServletActionContext.getServletContext();
            HttpServletResponse response = ServletActionContext.getResponse();



封装数据
    第一种,使用struts提供的ModelDriven机制,将数据封装到指定javabean (推荐)
        步骤:
            1 实现接口,并提供javabean泛型信息 implements ModelDriven<User>
            2 创建成员变量javabean实例,new User()
            3 实现方法:getModel,返回javabean实例
        拦截器中调用getModel方法获得javabean实例,然后进行数据填充
    第二种,将数据封装到action的属性
        步骤:给action添加属性(必须提供setter方法)
        struts会通过setter方法自动填充数据
    第三种,将数据封装到action的javabean属性的属性中
        步骤:
            给action添加属性,javabean对象(可以不new,必须提供给setter和getter方法)
            在页面表单元素的name使用ognl表达式直接为javabean中的属性赋值,如user.username,为action的user属性中的username属性赋值
        执行流程 
            页面 文本框name分别为 user.username 和 user.password
            则struts倒着填充,先填充user.password, 首先调用user的getter方法
                如果对象存在,调用password属性setter方法进行赋值
                如果对象不存在,或user的getter方法不存在,将创建User对象,并执行setter方法赋值
            填充user.username和上面相同



类型转换
    默认实现
        字符串  -->  基本类型或包装类型
        字符串  -->  时间类型(格式:yyyy-MM-dd , yyyy-MM-dd HH:mm:ss)
        字符串  -->  数组 | 集合(将复选框的值封装到数组或集合中)
    自定义实现--类型转换器
        实现接口:TypeConverter,建议继承默认实现类:DefaultTypeConverter
            复写方法:convertValue(java.lang.Object value, java.lang.Class toType) 
                浏览器 --> 服务器 (提交 String[]-->Date)
                    value ,浏览器提交的内容,String[] 通过request.getParameterValues("birthday")得到的
                    toType , 需要转换的类型 java.util.Date
                服务器 --> 浏览器 (struts标签 回显 Date-->String)
                    value , 标签回显时需要提供的数据 ,java.util.Date
                    toType, 浏览器需要的数据(字符串进行显示) , java.lang.String
        注册转换器-添加配置文件
            注册全局转换器,当前web项目都可以使用(对所有封装数据方式有效)
                文件名称:xwork-conversion.properties
                文件位置:src
                文件内容:需要转换的类型全限定类名=实现类全限定类名
                    例如:java.util.Date = util.MyDateConverter
            局部转换器,只对当前action有效。
                文件名称:Action类名-conversion.properties
                文件位置:与action同包
                文件内容:action属性=实现类全限定类名
                注意:只能使用action属性封装数据的方式,向javaBean封装数据时失效
        自定义日期转换器示例
            页面
                <s:form namespace="/" action="oneAction" method="post">
                    <s:textfield name="birthday" label="生日"></s:textfield>
                    <s:submit value="提交"></s:submit>
                </s:form>
            action.UserAction
                提供一个birthday属性,并提供getter和setter方法
            转换器实现类
                public class MyDateConverter extends DefaultTypeConverter {
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");//日期格式化工厂
                    @SuppressWarnings("rawtypes")
                    public Object convertValue(Object value, Class toType) {
                        try {
                            //浏览器 --> 服务器,String[] --> Date
                            if(java.util.Date.class == toType){
                                String[] values = (String[]) value;
                                String birthday = values[0]; //2014/5/15
                                java.util.Date date = dateFormat.parse(birthday);
                                return date;
                            }
                            //服务器 --> 浏览器,Date --> String
                            if(String.class == toType){
                                java.util.Date date = (Date) value;
                                String birthday = dateFormat.format(date);
                                return birthday;
                            }
                            return null;
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException();
                        }
                    }
                }
            注册转换器(二选一)
                全局:src/xwork-conversion.properties
                    java.util.Date=util.MyDateConverter
                局部:src/action/UserAction-conversion.properties
                    birthday=util.MyDateConverter



数据校验
    将浏览器已经封装到javabean中的数据进行合理校验。
    校验方式
        手动方法
            校验action全部方法
                必须实现接口Validateable,实现validate方法
                validate方法会在所有方法执行之前执行
                ActionSupport类已实现此接口
            校验action单个方法
                添加方法,方法名为validate+验证方法名称,例 add --> validateAdd
                验证方法将在方法执行之前先执行
            注意:
                先执行单个校验,再执行全部校验。
                在action中使用:this.addFieldError("username", "此处错误"); 添加错误信息,使目标方法不能继续执行(全局校验方法还会执行)
                手动验证时需要自己编写java代码进行验证
        xml配置方法
            添加xml配置文件即可,xml文件位置:action类同包
            校验action全部方法:
                文件名称:action类名-validation.xml
            校验action单个方法:
                文件名称:action类名-action配置name-validation.xml
                    action配置name 是<action>标签中的name属性的值
                    例:userAction_add --> UserAction-userAction_add-validation.xml
                    如果使用了通配符,如userAction_*,则按实际请求的路径写
            xml文件
                约束DTD位置:xwork-core-*.jar/xwork-validator-1.0.3.dtd
                基本内容:
                    <!DOCTYPE validators PUBLIC
                        "-//Apache Struts//XWork Validator 1.0.3//EN"
                        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
                    <validators>
                        <!-- 要验证的字段 -->
                        <field name="">
                            <!-- 验证器 -->
                            <field-validator type="">
                                <!-- 验证器参数,没有就不写-->
                                <param name="">值</param>
                                <!-- 不符合要求显示的消息提示 -->
                                <message></message>
                            </field-validator>
                        </field>
                    </validators>
                    注意:在<message>中可以使用${param的name}引用上面指定<param>的值
            struts提供验证器
                <field-validator type=""> type的值
                所有验证器位置:xwork-core-*.jar/最后一个包
                    /com/opensymphony/xwork2/validator/validators/default.xml
                常用验证器
                    required, requiredstring, int, date, expression, 
                    fieldexpression, email, url, stringlength, regex
                验证器的参数看源码setter方法
            校验文件示例
                <?xml version="1.0" encoding="UTF-8"?>
                <!DOCTYPE validators PUBLIC
                        "-//Apache Struts//XWork Validator 1.0.3//EN"
                        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
                <validators>
                    <!-- 用户名 -->
                    <field name="username">
                        <!-- 必填 -->
                        <field-validator type="requiredstring">
                            <message>用户名不能为空</message>
                        </field-validator>
                        <!-- 长度 -->
                        <field-validator type="stringlength">
                            <param name="minLength">3</param>
                            <param name="maxLength">12</param>
                            <message>用户名长度应为${minLength}-${maxLength}位</message>
                        </field-validator>
                    </field>
                    <!-- 密码 -->
                    <field name="password">
                        <!-- 必填 -->
                        <field-validator type="requiredstring">
                            <message>密码不能为空</message>
                        </field-validator>
                        <!-- 长度 -->
                        <field-validator type="stringlength">
                            <param name="minLength">6</param>
                            <param name="maxLength">12</param>
                            <message>密码长度应为${minLength}-${maxLength}位</message>
                        </field-validator>
                    </field>
                    <!-- 确认密码 -->
                    <field name="repassword">
                        <!-- 必填 -->
                        <field-validator type="requiredstring">
                            <message>确认密码不能为空</message>
                        </field-validator>
                        <!-- 匹配 -->
                        <field-validator type="fieldexpression">
                            <param name="expression">repassword==password</param>
                            <message>密码与确认密码不一致</message>
                        </field-validator>
                    </field>
                    <!-- 年龄 -->
                    <field name="age">
                        <!-- 必填 -->
                        <field-validator type="required">
                            <message>年龄不能为空</message>
                        </field-validator>
                        <!-- 范围 -->
                        <field-validator type="int">
                            <param name="min">3</param>
                            <param name="max">100</param>
                            <message>请输入正确的年龄</message>
                        </field-validator>
                    </field>
                    <!-- 生日 -->
                    <field name="birthday">
                        <!-- 必填 -->
                        <field-validator type="required">
                            <message>生日不能为空</message>
                        </field-validator>
                        <!-- 范围 -->
                        <field-validator type="date">
                            <param name="min">1930-01-01</param>
                            <param name="max">2010-01-01</param>
                            <message>请输入正确的生日</message>
                        </field-validator>
                    </field>
                    <!-- 邮箱 -->
                    <field name="email">
                        <!-- 必填 -->
                        <field-validator type="requiredstring">
                            <message>邮箱不能为空</message>
                        </field-validator>
                        <!-- 格式 -->
                        <field-validator type="email">
                            <message>邮箱格式不正确</message>
                        </field-validator>
                    </field>
                    <!-- 电话 -->
                    <field name="tel">
                        <!-- 必填 -->
                        <field-validator type="requiredstring">
                            <message>电话不能为空</message>
                        </field-validator>
                        <!-- 格式 -->
                        <field-validator type="regex">
                            <param name="regexExpression">((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)</param>
                            <message>电话格式不正确</message>
                        </field-validator>
                    </field>
                </validators>
        校验执行步骤:先进行数据封装-->执行xml配置的数据校验-->执行单个方法校验手动方法-->执行全部方法校验手动方法



拦截器
    拦截器栈:struts将多个拦截器组合成一个整体,存在先后顺序。
        默认拦截器:defaultStack
    拦截器,必须实现Interceptor接口,与过滤器filter相似。
        interceptor 拦截器:struts特有的功能,依赖于struts框架。放行:invocation.invoke();
        filter 过滤器:java web 提供过滤器程序。放行:chain.doFilter();
    默认拦截器执行顺序(了解)
        modelDriven     获得javabean,将javabean压入到root栈顶,等待数据填充
        fileUpload      如果有则获取上传文件
        params          数据填充,将数据依次填充到root栈的对象的属性中
        conversionError 校验封装数据时是否存在转换异常
        validation      校验
        workflow        检测是否有错误,有错误返回"input",没错误则放行
    自定义拦截器
        编写实现类
            实现Interceptor接口,重写intercept方法
                放行:invocation.invoke();
                获得请求的action类对象:invocation.getAction();
                添加错误信息:invocation.getAction().addFieldError("username", "此处错误");
                返回值会去struts.xml中寻找匹配结果
        注册拦截器栈
            位置:<package>中,<action>之前
            <interceptors>
                <!-- 注册拦截器 -->
                <interceptor name="拦截器名称" class="拦截器实现类"></interceptor>
                <!-- 注册拦截器栈 -->
                <interceptor-stack name="拦截器栈名称">
                    <!--默认拦截器栈-->
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <!--追加自己的拦截器-->
                    <interceptor-ref name="拦截器名称"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
        使用拦截器栈
            仅在指定action中使用
                位置:<action>中
                内容:<interceptor-ref name="拦截器栈名称"></interceptor-ref>
            一个包内所有action使用
                位置:<package>中,<action>之前,<interceptors>之后
                内容:<default-interceptor-ref name="拦截器栈名称"></default-interceptor-ref>



i18n
    国际化资源文件:baseName[_语言_国家|地区].properties
        例如:message_zh_CN.properties
    struest默认国际化配置文件
        位置:
            struts-core.jar /org/apache/struts2/struts-messages.properties
            xwork-core.jar /com/opensymphony/xwork2/xwork-messages.properties
        全局字段错误提示消息(不建议修改)
            xwork-messages.properties中
                xword.default.invalid.fieldvalue=Invalid field value for field "{0}".
            上面只是字段错误提示消息,其它错误提示消息在默认配置文件其它位置查找
    自定义资源文件
        位置
            action同包,对指定action有效
                文件名:action类名.properties , baseName是action类名
            action父包,所有的子包都有效
                文件名:package.properties , baseName是"package"固定串,不是包名
            全局配置
                位置任意,名称任意
                需要在struts.xml配置常量
                    struts.custom.i18n.resources=baseName,baseName2   -->多个资源文件使用逗号分隔 message,cn/itcast/message
                    即<constant name="struts.custom.i18n.resources" value="baseName|包/baseName"></constant>
        内容
            invalid.fieldvalue.字段名称=提示信息
            名称=值
            //以invalid.fieldvalue开头的键,为字段错误提示消息,当字段输入错误时,自动提示
            //其它错误消息固定key在struest默认国际化配置文件中查找
    使用
        可由ActionSupport类中的getText(key)获得value
        可使用sturts的国际化标签在页面显示
        以invalid.fieldvalue开头的键,为字段错误提示消息,当字段输入错误时,自动提示
    sturts的国际化标签
        <s:i18n name="cn/itcast/msg">   --> 加载指定位置的国际化资源文件,msg为文件名,不加后缀
            <s:text name="studentInfo"> --> 获得指定key的value
                <s:param>四儿</s:param> --> 给第一个位置设置值,用于填充获得内容的{n}位置
            </s:text>
        </s:i18n>



文件上传
    回顾
        浏览器
            <form method="post" enctype="multipart/form-data">
                <input type="file" name="imageName"/>
                <input type="submit" />
        服务器
            1 手动解析,request.getInputStream() ,获得请求体所有内容
            2 commons fileupload,第三方
            3 servlet 3.0 Part对象,使用注解
            4 struts提供上传支持
    struts文件上传
        必须提供三个属性setter方法获得所有内容
            File image;             //记录文件内容,image为表单提交时file控件name的值
            String imageFileName;   //记录文件名称,image同上,FileName为固定字符串
            String imageContentType;//记录文件类型,image同上,ContentType为固定字符串
        多文件上传,将以上三个属性的类型变为数组或集合即可.注意:多文件上传表单中多个file控件的name应一致
        文件拷贝:FileUtils.copyFile(File srcFile,File destFile); --commons-io.jar中的工具类,struts2自带
        方法完成后struts会自动将原来的文件删除
    struts文件上传常量
        struts.multipart.parser=jakarta     ,确定struts解析文件上传方法,apache commons fileupload
        struts.multipart.maxSize=2097152    ,默认大小,2M ,注意不能写 1024*1024*2
    扩展名限制
        在struts.xml的<action>中添加
            <interceptor-ref name="defaultStack">
                <param name="fileUpload.allowedExtensions">.jpg,.png</param>
            </interceptor-ref>
        上面设置的是允许的扩展名,不符合会返回input
        上面是给某个拦截器设置参数的方式,fileUpload为拦截器名称,allowedExtensions为属性名称
    文件上传action示例
        public class UserAction extends ActionSupport {
            private File image; //表单名称为image
            private String imageFileName;
            private String imageContentType;
            public void setImage(File image) {
                this.image = image;
            }
            public void setImageFileName(String imageFileName) {
                this.imageFileName = imageFileName;
            }
            public void setImageContentType(String imageContentType) {
                this.imageContentType = imageContentType;
            }
            public String upload(){
                try {
                    String dir = "/uploadFile";//文件存放路径
                    dir = ServletActionContext.getServletContext().getRealPath(dir);
                    File destFile = new File(dir,imageFileName);
                    FileUtils.copyFile(image, destFile);//原来的文件自动删除
                } catch (Exception e) {
                    System.out.println("文件拷贝失败");
                }
                return SUCCESS;
            }
        }



文件下载
    回顾
        将文件资源流发送到浏览器,response.getOutputStream()
        设置响应头:content-disposition = attachement;filename=1.jpg
        发送流
    步骤
        1.在action中
            添加一个InputStream属性,并提供get方法,将要发送的数据放到属性中
            添加一个String属性fileName,并提供get方法,将文件名称放到属性中(名称不是固定的,是和下面对应的)
        2.在struts.xml中配置result
            <result name="success" type="stream">
                <param name="inputName">属性名称</param>
                <param name="contentDisposition>attachment;filename=${fileName}</param>
            </result>
            说明
                inputName设置action的流属性名称
                contentDisposition设置响应头,说明文件时需要下载的
                ${fileName}表示在action类中获取fileName属性的值,所以在action中要提供fileName属性
                可选操作:<param name="contentType>${contentType}</param>
                contentType设置文件类型,需要在action中提供属性,一般赋值方法:contentType=ServletActionContext.getServletContext().getMimeType(fileName);
        文件名称中文乱码问题还是fileName = new String(fileName.getBytes("gbk"),"iso8859-1");
        如果用户取消下载会抛异常,可使用插件解决struts2-sunspoter-stream-1.0.zip



ognl表达式
    OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,比EL更强大的表达式语言(开源项目)
    Struts2框架使用OGNL作为默认的表达式语言。
        在JSP中执行OGNL表达式需要struts标签,<s:property>将ognl表达式的结果发送到浏览器 ,等价于<c:out/>
    优势
        支持对象方法调用
        支持类静态的方法调用和常量访问
        支持赋值操作和表达式串联 ,user.username
        访问OGNL上下文(OGNL context)和ActionContext; 
        操作集合对象。
        可以直接new一个对象
    语法
        对象方法调用
            <s:property value="'abc'.length()"/>
            <s:property value="page"/>  //会访问action中的属性,调用getPage方法(如果存在的话)
        类静态的方法调用和常量访问
            表达式的格式: @[全限定类名]@[方法名 | 常量名]
                <s:property value="@java.lang.Math@PI"/>
                <s:property value="@java.lang.Math@PI"/>
            默认情况静态方法不能执行,需要设置struts常量
                struts.ognl.allowStaticMethodAccess=false
        支持赋值操作和表达式串联 
            <s:property value="#page.data[0].birthday"/><br>
            <s:property value="#page.data[0].birthday='2000-1-1'"/><br>
        访问OGNL上下文(OGNL context)和ActionContext; 
        操作集合对象。
        可以直接new一个对象
    特殊符号
        # : 通过key获得context值,可以用于创建对象
            创建List:{'元素1','元素2','元素3'}
            创建Map:#{'key1':'value1','key2':'value2'}
        % : 在struts标签中确定语法
            %{ognl表达式}:表示里面的内容必须按照ognl表达式去执行
            %{'字符串'}:表示里面的内容为普通字符串
        $ : 在配置文件struts.xml 和 国际化资源文件*.properties 使用${ognl表达式},从值栈中获取内容。



ValueStack
    值栈:struts用于传递数据的对象。
        一个action对应一个值栈,贯穿整个action生命周期。在action创建之后就有一个值栈,一次请求对应一个action和一个值栈。请求结束,action销毁,值栈也销毁。
        struts将值栈对象放置到servlet 的request域中
        值栈实际上是一个接口,在Struts2中利用ognl时,实际上使用的是实现了该接口的OgnlValueStack类.所以,struts2的值栈对象其实是OgnlValueStack类的一个实例
    获得值栈
        1 通过Action上下文:ActionContext.getContext().getValueStack() 
        2 通过指定的属性名称获得:ServletActionContext.getRequest().getAttribute("struts.valueStack");
    值栈结构
        root和context是OgnlValueStack实例的两个属性
        root : 类型为CompoundRoot,extends ArrayList 底层是List。称为:对象栈,只能存放对象,对象不能添加名称。
            提供了压栈和出栈的操作(方法),模拟栈结构.
            struts2默认将当前action实例放入到栈顶
        context:类型为Map<String,Object> ,可以给保存数据添加名称,通过名称获得指定对象。
            struts规定了若干固定key,可以间接对servlet不同的域进行操作
                application ,application作用域内容。Map<属性名称,属性值>
                session,session作用域内容。Map<属性名称,属性值>
                request,request作用域内容。Map<属性名称,属性值>
                attr,依次的page/request/session/application作用域的所有值。Map<属性名称,属性值>
                parameters,请求参数 ,Map<name,values>
    root操作
        root就是平常所说的值栈
            ValueStack vs = ActionContext.getContext().getValueStack();
        存放数据
            push(Object obj)    //压栈,将对象压入到栈顶
            set(key,value)      //将key-value存入栈顶的Map中(栈顶如果不是Map,则先创建,再将Map压入栈顶)
        获得数据
            <s:property value="名称" />     //通过指定属性获得第一个值,匹配root对象栈中对象的属性或Map的key.
            <s:property value="top" />      //获得栈顶的数据
            <s:property value="[2]" />      //从第三个开始,将之后的所有内容组成一个新的栈,并输出
            <s:property value="[2].top">    //获得新栈的第一个值
    context操作
        context是一个Map,可以间接对servlet不同域进行操作
            ActionContext.getContext()可以获得ActionContext对象
            ActionContext对象的put和getSession等方法其实是向context中添加和获得数据
        存放数据
            ActionContext.getContext().put(key,value) ,直接添加到context对象中,不会存到request域中,不过用request可以取到(进行了方法增强)
            ActionContext.getContext().getSession().put(key,value) , 添加到context对象固定key为session对应的Map中,会存到session作用域中
            ActionContext.getContext().getApplication().put(key,value) 添加到context对象固定key为application对应的Map中,会存到application作用域中
        获得数据
            通过 #key获得数据, <s:property value="#session.person.personName"/>
    获取数据的特殊方法
        <s:property value="gf"/>
            底层使用findValue(gf)
                先从root对象栈中获取内容
                如果没有,再从content获取
        <s:property value="#request.gf"/> <br/>
            request被struts使用装饰者默认进行修改(方法增强)
                request实现类 org.apache.struts2.dispatcher.StrutsRequestWrapper ,<%=request.getClass() %>
            struts对request的getAttribute方法进行增强
                先从servlet 的request作用域获得数据
                如果没有,再从值栈获得,执行findValue
                    先从root对象栈中获取内容
                    如果没有,再从content获取
    使用标签查看值栈 <s:debug/>
    因为request.getAttribute方法被增强,可以获取到值栈中的值,所以el表达式也可以获取值栈中的值



struts标签
    好处 : 回显,自动提示错误消息(在每个表单元素上方添加<s:fielderror>标签),url自带JSESSIONID,布局
    引入标签库 : <%@ taglib uri="/struts-tags" prefix="s" %>
    常用标签
        <s:property>    获取值栈中的数据
            value       表达式
            default     默认值,当表达式的值为空时,会显示默认值
            escapeHtml  是否进行html转义
        <s:set>         将数据放置到作用域
        <s:url>
            namespace   action的namespace
            action      action的name
            var         变量名
    流程控制标签
        <s:iterator>    遍历
            value       要遍历的数据
            var         将当前压入栈顶
            begin       开始值
            end         结束值
            status      将遍历信息存储在context中,可用属性count,index等 如 #status值.index
            注意:每次循环开始默认将集合中的每一个对象压入到栈顶,下一次循环弹出.使用var,可同时在context中起名存储
        <s:if><s:elseif><s:else>
            test        条件
    表单标签
        在表单标签中class和style属性用cssClass和cssStyle属性指定
        在表单标签中使用theme属性修改标签模板,则包含的标签都会使用统一的模板,如theme="simple"
        <s:fielderror>  显示用户输入的错误提示
        <s:actionerror> 显示action的错误提示
        <s:form> 表单
            namespace   struts.xml中<package>的namespace
            action      struts.xml中<action>的name
            enctype     和普通form相同
            method      和普通form相同
        <s:submit> 提交按钮
            value       显示文本
        <s:textfield> 文本框
            name        同原来的name
            label       前面的文本,simple风格无效
        <s:password> 密码框
            showPassword    显示value属性,默认为false,不显示
        <s:hidden> 隐藏域
        <s:date> 格式化显示时间
            name        要显示的属性
            format      格式
    表单标签2
        <s:checkboxlist> 复选框列表
            name        必须
            list        取值为list集合或map集合,使用ognl表达式
                            如果取值为list,则value和显示的数据一致
                            如果取值为map,则value为map的key,显示的数据为map的value
            value       默认选中,通常要使用%{值}
        <s:radio> 单选框列表
            使用方法同<s:checkboxlist>
        <s:select> 下拉列表
            使用方法同<s:checkboxlist>
            headerKey       默认头的value
            headerValue     默认头的显示文本
            listKey         value为集合中的javaBean的哪个属性
            listValue       显示的数据为集合中的javaBean的哪个属性
        示例
            <s:select list="#{'1':'小班','2','大班'}" name="edu"
                headerKey="" headerValue="--请选择--">
            </s:select>
            或
            <s:select list="#request.sexList" name="sexID" 
                listKey="ddlCode" listValue="ddlName"
                headerKey="" headerValue="请选择">
            </s:select>
    注意
        在<s:if>标签的test属性中,注意test="a==1"和test="a=='1'",两者有截然不同的效果
        在<s:set>的value属性中,将变量赋值为1:value="%{'1'}",不能为value="1"



token(struts令牌机制)
    回顾:一次性验证码原理
    token机制,防止表单重复提交。 (验证码防止表单重复提交已经解决方案)
        1.服务器缓存一份数据,浏览器也要缓存相同一份数据
        2 浏览器提交数据,自动获得服务器缓存的数据
            比较,并删除服务器缓存数据
                相同,正常请求
                不相同,重复提交
    使用token
        1 在表单中添加一个标签<s:token/> (会生成一个随机数,保存到session,同时在页面生成一个隐藏域,记录值)
        2 在struts.xml中配置,添加struts的token拦截器 (拦截器做的事:获取隐藏域的value与session对比,并删除session的数据)
        例:
            注册新拦截器栈
                在<package>标签中添加
                <interceptors>
                    <interceptor-stack name="tokenStack">
                        <interceptor-ref name="defaultStack"></interceptor-ref>
                        <interceptor-ref name="token"></interceptor-ref>
                    </interceptor-stack>
                </interceptors>
            使用新拦截器栈
                在<action>标签中添加
                <interceptor-ref name="tokenStack"></interceptor-ref>
            配置token错误处理页
                <result name="invalid.token>/form.jsp</result>
                在错误处理页可以使用<s:actionerror>标签 显示错误提示


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值