美文网首页
struts2入门

struts2入门

作者: 呦後 | 来源:发表于2017-08-07 15:51 被阅读0次

    [TOC]

    struts2

    概念:Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。


    1、开发环境搭建

    1、拷jar包, 在apps包下,blank>WEB-INF>lib

    2、拷配置文件, 在apps包下,blank>WEB-INF>src>java>struts.xml

    3、拷过滤器配置, 在apps包下, blank>WEB-INF>web.xml

    4、将自己新建的action类配置到struts.xml中

    public String execute(){
            return "tohello";
        }
    
    
     <package name="default" namespace="/" extends="struts-default">
    <!-- package的namespace与action的name组成 浏览器访问路径 class是自己新建action的全类名 -->
    <action name="hello"  class="com.hemi.action.ActionTest">
        <!-- name自己新建action类return的字符串  /hello.jsp跳转的目标jsp -->
        <result name="tohello">/hello.jsp</result>
        </action>
    </package>
    

    2、struts2 核心类:StrutsPrepareAndExecuteFilter


    3、struts2 执行顺序

    1.jpg

    4、配置文件

    • constant 标签:

      • name="struts.devMode" value="true" 设置配置文件更改不会自动重新加载
      • name="struts.i18n.encoding" value="UTF-8" 设置框架的编码格式,默认UTF-8
      • name="struts.action.extension" value="do,," 设置页面访问时后缀名 默认action,, ,,表示加或者不加后缀都能访问
    • package 标签:

      • name:用来区分不同的action
      • extends:必须默认继承 struts-default
    • action 标签: 配置action处理类路径 和映射路径

      • method:指明要调用action中的哪个方法,不写默认执行execute方法
    • result 标签: 配置结果页面

      • name:逻辑视图名,是action类返回的逻辑视图名
      • 文本内容:物理视图名(jsp文件)
    • include 标签:用来引入其他配置文件,适合团队分模块开发


    5、action编写方式

    1、自定义类,编写execute方法

    2、实现Action接口

    3、继承ActionSupport类


    6、action方法访问方式

    1、传统访问,通过method属性指明

    2、通配符访问 *

    <!-- {表示第几个*号是方法名}   根据*输入的方法名 并根据该方法返回的字符串与resultname比对进行相应的跳转-->
    <action name="user_*" class="........."  method="{1}">
        <result name="ok"></result>
        <result name="fail"></result>
    </action>
    

    3、动态方法调用 ! action名!方法名.后缀 放开动态调用的常量是:struts.enable.DynamicMethodInvocation 为true 开启


    7、跳转方式

    • result 标签:type 属性来控制页面的跳转方式
      • jsp页面跳转(默认)转发 dispatcher 重定向 redirect
      • Action之间跳转 : 转发 chain 重定向redirectAction
            <!-- 默认转发 dispatcher -->
            <result name="login">/login.jsp</result>
            <result name="register">/register.jsp</result>
            <!-- jsp页面的重定向 -->
            <result name="menu" type="redirect">/menu.jsp</result>
            <!-- action之间的重定向 -->
            <result name="fail" type="redirectAction">user_register</result>
    

    注意不同papackage标签的Action之间的跳转 需要注入
    通过两个param标签(放在result标签内) 注入 name="actionName" 和 name="nameSpace"

        <result name="success" type="redirectAction">
            <!-- 另一个package中action的name -->
            <param name="actionName">hello</param>
            <!-- 另一个package的namespace -->
            <param name="nameSpace">/</param>
        </result>
    

    8、动态结果页面配置

    1、在action类中定义一个字符串变量,并提供get方法 在每个方法内设置该字符串来决定物理视图名,指定要跳转的目标页面

    public class MyAction {
        private String view;
        public String getView() {
            return view;
        }
        public void setView(String view) {
            this.view = view;
        }
        public String test1(){
            setView("test1.jsp");
            return "ok";
        }
        public String test2(){
            setView("test2.jsp");
            return "ok";
        }
        public String test3(){
            setView("test3.jsp");
            return "ok";
        }
    }
    

    2、在result 的文本配置成获取物理视图属性 通过${action中的字符串变量名}

    <action name="test_*" class="com.hemi.action.MyAction" method="{1}">
        <result name="ok">/${view}</result>
    </action>
    

    9、Servlet API的操作,也就是获取参数

    1、耦合方式 ServletActionContext.getRequest()

    //耦合方式
            HttpServletRequest req = ServletActionContext.getRequest();
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            System.out.println(username);
            System.out.println(password);
            if ("admin".equals(username) && "123".equals(password)) {
                req.setAttribute("username", username);
                req.setAttribute("password", password);
                setView("success.jsp");
                return "ok";
            }
            setView("login.jsp");
            return "fail";
    

    2、解耦方式 ActionContext.getContext()

            //解耦方式
            ActionContext context = ActionContext.getContext();
            Map<String, Object> map = context.getParameters();
            
            String[] username = (String[]) map.get("username");
            setView("test3.jsp");
            return "ok";
    

    3、ioc注入 实现ServletRequestAware接口在类里声明HttpServletRequest
    并重写setServletRequest方法 在里面写this.request=req;(给类中的全局变量赋值)

    public class MyAction implements ServletRequestAware {
        private String view;
    private HttpServletRequest request;
    //ioc注入
    public String test2() {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            System.out.println(username);
            System.out.println(password);
            if ("admin".equals(username) && "123".equals(password)) {
                request.setAttribute("username", username);
                request.setAttribute("password", password);
                setView("success.jsp");
                return "ok";
            }
            setView("login.jsp");
            return "fail";
        }
    
        @Override
        public void setServletRequest(HttpServletRequest req) {
            this.request=req;
        }
        }
    

    10、数据校验

    1、首先继承ActionSupport

    2、校验全部方法 重写 validate方法

    3、校验指定方法 自定义方法 validate+校验的方法名(注意:方法首字母大写)

    4、添加校验错误信息 addFieldError

            //System.out.println("校验test1方法");
            String username = request.getParameter("username");
            if (username.length()==0) {
                addFieldError("username", "用户名不能为空");
            }
    

    5、配置文件中加一个result name为input

    <result name="input" type="redirect">/login.jsp</result>
    

    11、配置结果页面

    • 局部结果页面
    <action name="user" class="com.hemi.action.UserAction" >
        <result "ok">/login.jsp</result>
    </action>
    
    • 全局结果页面 同package标签内所有action都可以访问
      • 使用global-results标签 注意:
        • 放在package标签内
        • 一定要放在所有Action配置之前
        • 作用范围只有同package标签内的action
    <global-results>
        <result name="error">/error.jsp</result>
    </global-results>
    

    12、异常处理

    • 局部异常处理 通过exception-mapping 在action标签下来捕获异常
      • result属性: 表示要跳转的逻辑视图名就是下面result标签的name
      • exception属性:指明要捕获的异常类型
    <action name="hello" class="com.hemi.action.ActionTest">
        <exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
        <result name="error">/error.jsp</result>
    </action>
    
    • 全局异常处理 通过global-exception-mappings 写在全局结果页面下
      • 子标签exception-mapping result属性:表示要跳转的逻辑视图名
      • exception属性:指明要捕获的异常类型
    <!-- 全局结果页面 -->
    <global-results>
        <result name="er">/error.jsp</result>
    </global-results>
    <!-- 全局异常处理  如果是hello这个action报异常 先在自己内部结果页面找有没有er  没有再找全局结果页面有没有er-->
    <global-exception-mappings>
        <exception-mapping result="er" exception="java.lang.Exception"></exception-mapping>
    </global-exception-mappings>
    
    <action name="hello" class="com.hemi.action.ActionTest">
        <result name="er">/common.jsp</result>
    </action>
    

    13、参数封装

    • 属性封装
      -在Action中定义与表单中name值相同的全局变量,并提供set方法,会自动帮我们把表单中的数据封装到对应变量中
        private String name;
        private int age;
        private String sex;
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        @Override
        public String execute() throws Exception {
            System.out.println(name + "---------" + age + "--------" + sex);
            return NONE;
        }
    
    • 对象封装(表达式封装)
      • 新建一个实体类
      • 在Action中 定义一个全局的对象变量 提供get set方法,表单中的name属性值为:对象.属性名
        private User user;
        public void setUser(User user) {
            this.user = user;
        }
        public User getUser() {
            return user;
        }
    
        @Override
        public String execute() throws Exception {
            System.out.println(user);
            return NONE;
        }
    
    <form action=""  method="post">
        <input type="text" name="user.name">
        <input type="text" name="user.sex">
        <input type="text" name="user.age">
    </form>
    
    • 模型驱动封装
      -定义一个全局对象变量并实例化 实现一个ModelDriven<T>接口,并重写其中的抽象方法getModel() 将全局对象变量 return出去
    public class UserAction  implements ModelDriven<User>{
    private User user =new User();
    
    @Override
    public String execute() throws Exception {
            System.out.println(user);
            return NONE;
        }
    
    @Override
        public User getModel() {
            return user;
        }
    }
    

    注:封装集合 表单中用list[0(index)].属性


    14、如何传递数据到前台界面

    通过request域对象的setAttribute方法设置

    值栈来存,通过ognl表达式来取 servlet和action区别? servlet是单实例 action是多实例

    • 值栈的位置,位于每个action中且 一次action运行保证唯一 同一个action 两次运行 值栈不同。
    • 值栈结构
      • CompountRoot: root值栈 底层是list集合
      • OgnlContext:map栈 底层map结构
    • 如何向root值栈中存值

    1...使用set方法 会向root栈中压入一个map集合对象 然后把值存入map集合中

    //通过set方法
    stack.set("name", "tom");
    

    2...使用push方法 直接值对象的引用压入root栈中

    //通过push方法
    stack.push("adsfadfafa");
    

    3...使用属性的get方法 不会压入新对象引用 直接存放在当前action引用的下面 (实际开发中经常使用)

    
    private String msg;
    public String getMsg() {
        return msg;
    }
    private User user;
    public User getUser() {
        return user;
    }
        
    private List<User> list;
    public List<User> getList() {
        return list;
    }
    @Override
    public String execute() throws Exception {
        ActionContext context = ActionContext.getContext();
        ValueStack stack = context.getValueStack();
    
        //通过get方法    定义一个全局变量 并提供get方法  然后在这里赋值
        msg="dfaaadfaf";
            
        //通过get方法 存对象
        user=new User(1,"da","man");
            
        //通过get方法  存集合
        list=new ArrayList<User>();
        list.add(new User(2, "jack", "man"));
        list.add(new User(3, "marry", "woman"));
        return "ok";
        }
    

    页面中查看 值栈的方法:在jsp页面中导入标签库<%@ taglib prefix="s" uri="/struts-tags" %> 并写 <s:debug></s:debug>

     <s:debug></s:debug>
    
    2.jpg
    • 取出root值栈中的数据 通过struts2标签库加OGNL表达式来取

    取出get方法存入的值

    <!-- 取属性:直接取 -->
    <s:property value="msg"/>
    <!-- 取对象:通过.属性来取 -->
    <s:property value="user.name"/>
    <s:property value="user.sex"/>
    <!-- 取集合 -->
    <!-- 方式一list[0].属性名 -->
    <s:property value="list[0].name"/>
    <s:property value="list[0].sex"/>
    <!-- 方式二 -->
    <s:iterator value="list">
        <s:property value="name"/>
        <s:property value="sex"/>
    </s:iterator>
    <!-- 方式三 效率比方式二高-->
    <s:iterator value="list" var="user1">
        <!-- 使用var 会把root栈中的值拷贝一份到map栈 取值需要特殊符号# -->
        <s:property value="#user1.name"/>
        <s:property value="#user1.sex"/>
    </s:iterator>
    
    

    通过jstl和el表达式来取

    <c:forEach items="${list}" var="uu" >
        ${uu.name}<br>
        ${uu.sex}
    </c:forEach>
    

    问题: 为什么能取出来?
    因为值栈是对域对象的增强,内部会从值栈中取出数据放到域对象中

    取出set方法存入的值

    <!-- 取属性:通过set存入时的key来取 -->
    <s:property value="msg"/>
    
    <!-- 取对象:通过set存入时的key.属性名来取 -->
    <s:property value="user.name"/>
    <s:property value="user.sex"/>
    <!-- 取集合:与get一样-->
    

    取出push方法存入的值

    <s:property value="[0].top"/>
    

    15、OGNL表达式的使用 (对象导航语言)

    获取域对象里的值

    • 通过#号+域对象在map栈中的引用.域对象中的key值
    //向request域对象中存值
    ServletActionContext.getRequest().setAttribute("uid", "我是request域对象");
    //向application域对象中取值
    ServletActionContext.getServletContext().setAttribute("ap","我是application域对象")
    
    <!-- 向request域对象中取值 -->
        <s:property value="#request.uid"/><br>
    <!-- 向application域对象中取值 -->
        <s:property value="#application.ap"/><br>
    

    标识ognl表达式

    <!--  加上%才能识别 ognl表达式 不然只是输出#application.ap字符串 -->
    <s:textfield value="%{#application.ap}"/>
    

    $ 主要用于国际化验证的配置文件中取数据(例如:动态结果页面)

    投影过滤 {}

    <!-- 取出list里的所有name -->
    <s:property value="list.{name}"/>
    

    16、struts2 拦截器

    拦截器与过滤器区别:、过滤器理论上拦截一切资源 、拦截器(struts2中)只能拦截方法
    1、自定义类 实现Interceptor接口
    2、自定义类 继承AbstractInterceptor
    3、自定义类 继承MethidFilterInterceptr 能拦截到具体方法 推荐

    配置使用:

    (局部拦截器)

    1、声明拦截器

    <interceptors>
        <interceptor name="myInter" class="自定义拦截器类全类名" />
    </interceptors>
    

    2、在action标签中使用拦截器

    <action>
     <interception-ref name="myInter" />
     </action>
    

    3、如何放行action中指定方法[只有继承MethidFilterInterceptr的拦截器才能忽略指定方法(放行指定方法)]

    <action>
     <interception-ref name="myInter" >
        <param name="excludeMethods">忽略的方法名1,忽略的方法名2.....</interception-ref>  
     </interception-ref>
     </action>
    

    (全局拦截器)

    1、声明自定义拦截器

    2、定义拦截器栈

    3、引入自定义拦截器和 系统默认拦截器栈![注意:必须引入 否则系统自带的拦截器都不能使用]

    4、引入自定义拦截器栈

    <interceptors>
        <!-- 声明自定义拦截器 -->
        <interceptor name="myInter" class="com.hemi.interception.MyInterception"></interceptor>
        <!-- 定义拦截器栈 -->
        <interceptor-stack name="myStack">
            <!-- 引入自定义拦截器 -->
            <interceptor-ref name="myInter">
                <!-- 使该拦截器忽略指定方法 -->
                <param name="excludeMethods">test1</param>
            </interceptor-ref>
            <!-- 引入系统默认的拦截器栈 -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </interceptor-stack>
    </interceptors>
    
    <!-- 全局引入拦截器栈 -->
    <default-interceptor-ref name="myStack"></default-interceptor-ref>
    

    额外知识:当编写action时,没有指明class 默认使用ActionSupport类 result必须是success

    <!-- 访问hello就会到hello.jsp页面 执行的是ActionSupport类里的excute方法 -->
    <action name="hello">
        <result name="success">/hello.jsp</result>
    </action>
    

    额外知识:配置默认处理action 启动服务器没输入地址或者输入的地址不存在 会默认调用这个action

    <default-action-ref name="hello"></default-action-ref>
    <action name="hello">
        <result name="success">/hello.jsp</result>
    </action>
    

    17、struts2 常用标签的使用

    1、UI标签

    (1)表单标签 form

       <s:form action="" method="">
            <s:textfield name="username" label="user"/> <!-- 等同 user:<input type="text" name="username">-->
            <s:textfield name="pwd" label="password"/> <!-- 等同 password:<input type="password" name="pwd">-->
            <s:radio list="#{'0':'woman','1':'man'}" name="sex" label="gender"/>
            <!-- 等同 gender:<input type="radio" value="0" name="sex">woman
                            <input type="radio" value="1" name="sex">man-->
            <s:submit value="提交"/>
       </s:form>
    

    (2)非表单标签

    2、通用标签 if elseif else iterator debug property

    (1)if标签

    <s:if test="%{条件}">
       
    </s:if>
    

    (2)iterator 迭代标签 等等、、、、、

    18、文件的上传

    • 编写前端页面,上传数据的表单
    <form action="upload" method="post" enctype="multipart/form-data">
        请上传文件:<input type="file" name="temp"> <!-- 此处name为action类中 File定义的变量名  -->
        <br>
            <input type="submit" value="upload">
    </form> 
    
    • 编写action 定义三个全局变量 提供get方法 set也可以加上
      • File src 上传文件的临时目录
      • String srcFileName 文件名
      • String srcContentType 文件类型
    private File temp;
    private String tempFileName;
    private String tempContentType;
    
    public File getTemp() {
        return temp;
    }
    public void setTemp(File temp) {
        this.temp = temp;
    }
    public String getTempFileName() {
        return tempFileName;
    }
    public void setTempFileName(String tempFileName) {
        this.tempFileName = tempFileName;
    }
    public String getTempContentType() {
        return tempContentType;
    }
    public void setTempContentType(String tempContentType) {
        this.tempContentType = tempContentType;
    }
    
    • 在Action方法内写、、
    //获取路径
    String path =ServletActionContext.getServletContext().getRealPath("/");
    File destFile=new File(path,tempFileName);
    FileUtils.copyFile(temp, destFile);
    return "ok";
    

    上传文件到自己指定路径时
    1、在web.xml中配置 绝对路径

    <context-param>
        <param-name>path</param-name>
        <param-value>D:\Tomcat\webapps\images</param-value>
    </context-param>
    

    2、获取路径通过getInetParameter

    String path = ServletActionContext.getServletContext().getInitParameter("path");
    File destFile=new File(path,tempFileName);
    FileUtils.copyFile(temp, destFile);
    return "ok";
    

    19、日期转换器

    a、自定义类继承数据转换类 StrutsTypeConverter

    b、重写抽象方法

    c、在src下 新建并编写配置文件 xwork-conversion.properties

    20、json

    相关文章

      网友评论

          本文标题:struts2入门

          本文链接:https://www.haomeiwen.com/subject/jruecxtx.html