Struts2

概述

  • 用我们自己的话来说: struts是web层框架, 相当于Servlet

  • 作用: 1. 获得请求参数 2. 调用业务 3. 分发转向

常用的WEB层框架

Struts2入门

1.环境下载

    下载地址

      http://struts.apache.org/download.cgi;

2. 导入jar

​ struts的jar比较多,可以从Struts官方提供的demo中拿到必要的jar就行. 在apps/struts2-blank项目下

3. 编写Action类

  • 新建一个类,里面定义一个方法

 /**
  *一,创建了一个普通的类 ,定义了一个execute()方法
  *好比我们之前:创建了一个ProductServlet,然后创建了一个doGet()方法一样
  *二, 配置Action 好比配置Servlet一样,只不过不在web.xml里面配置,自己整了一套
 *    在src目录下struts.xml的文件里面配置
 */
 public class ActionDemo {
     public void execute(){
         System.out.println("收到到了请求...");
     }
  }

4. 配置struts.xml文件

  • 在src底下新建一个xml 名称为 struts.xml. 在struts.xml里面配置action

 <?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="test" extends="struts-default" namespace="/">
         <!--一个请求对应一个Servlet, struts2里面一个请求配置一个Action  -->
         <action name="demo" class="demo.web.ActionDemo"></action>
     </package>
 </struts>

注意:

  1. struts.xml文件名不可随意取,必须叫做struts.xml

  2. struts.xml必须放在src类路径下

  3. 到struts的核心包中可以找到struts-2.3.dtd文件(建议配置本地的dtd,没网情况下也可以使用...)

5. 前端控制器配置

  • 在web.xml下配置

 <!--前端控制器(过滤器)  -->
 <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>
其实就是在web.xml中配置struts2的filter

6. 编写访问路径,进行测试

http://localhost:8080/Struts2/demo

三,Struts.xml中的配置详解

  • Eg

 <struts>
     <!--一,package指的就是一组请求的集合.(eg: 一个模块就创建一个package)
         name属性: package的名字, 不要重复就好
         extends属性: 继承的意思;当前我们自己的test包继承了struts-default这个包, 也就意味着test包拥有struts-default这个包定义的功能
         namespace属性: 名称空间; 用意在于访问Action的时候加了一层路径
                              eg: 当前配置的是 / , 路径 http://localhost:8080/Struts2/demo01
                                    当前配置的是 /test , 路径 http://localhost:8080/Struts2/test/demo01
         abstract属性: 抽象的意思; 如果设置了为ture, 表明当前包没有实际用途,被别的包继承
        -->
     <package name="test" extends="struts-default" namespace="/">
         <!--二. 一次请求就配置定义一个action标签
             name属性: action的名字,说白了就是当前Action的访问路径. (不要重复)
             class属性: 当前Action类的全限定名
             method属性: 处理当前请求的方法名(说白了就是Action类里面的方法名),默认执行execute
           -->
         <action name="demo01" class="demo.web.ActionDemo01"></action>
         <action name="fun02" class="demo.web.ActionDemo01" method="login">
             <!--三, 通过 result配置结果(分发转向)
                 name属性: 结果的名字.说白了就是处理当前请求方法的返回值
                 type属性: 配置跳转的类型,默认是转发到页面(明天讲)
                  值: 就是跳转的路径.
              -->
             <result name="loginSuccess">
                 /login.jsp
             </result>
         </action>
     </package>
 </struts>
  • <struts>
    <!--一,package指的就是一组请求的集合.(eg: 一个模块就创建一个package)
    name属性: package的名字, 不要重复就好  
    extends属性: 继承的意思;当前我们自己的test包继承了struts-default这个包, 也就意味着test包拥有struts-default这个包定义的功能
    namespace属性: 名称空间; 用意在于访问Action的时候加了一层路径
    eg: 当前配置的是 / , 路径 http://localhost:8080/day42A_Struts2/demo01
     当前配置的是 /test , 路径 http://localhost:8080/day42A_Struts2/test/demo01
    abstract属性: 抽象的意思; 如果设置了为ture, 表明当前包没有实际用途,被别的包继承
      -->
    <package name="test" extends="struts-default" namespace="/">
    <!--二. 一次请求就配置定义一个action标签
    name属性: action的名字,说白了就是当前Action的访问路径. (不要重复)
    class属性: 当前Action类的全限定名
    method属性: 处理当前请求的方法名(说白了就是Action类里面的方法名),默认执行execute
     -->
    <action name="demo01" class="com.itheima.web.ActionDemo01"></action>
    <action name="fun02" class="com.itheima.web.ActionDemo01" method="login">
    <!--三, 通过 result配置结果(分发转向)
    name属性: 结果的名字.说白了就是处理当前请求方法的返回值
    type属性: 配置跳转的类型,默认是转发到页面(明天讲)
    值: 就是跳转的路径.
    -->
    <result name="loginSuccess">
    /login.jsp
    </result>
    </action>
    </package>
    </struts>

1.package标签

1.1概述

​ 一个package就是一组业务的集合, 也就是说一个模块对应一个package . 举个例子 : 我们针对用户的操作有很多请求 . 用户的添加 、 用户的删除 、用户的修改...

1.2属性解释
  • name属性:package的名字,一般不建议重复

  • extends属性: 这个package 继承指定的package 。 struts-default 这也是一个package 这里面包含了很多的拦截器, 一般我们都会使用到这些拦截器。

  • namespace属性:翻译过来是命名空间 用意就是在根目录下面再加一个子路径才能访问到action。


    如果namespace值是/, 通过localhost:8080/项目名/add来访问
    如果namespace值是/user, 通过localhost:8080/项目名/user/add来访问
    好处: 在写请求路径的时候,意思更加明确,看路径就可以确定对应是哪个模块
  • abstract:抽象。用来被其他package继承的

2.action标签

2.1概述

​ 一个动作就是一个Action ,通俗一点就是一个请求在xml配一个Action 。和以前的一个请求配一个Servlet 相似

2.2 属性解释
  • name: 配置action的访问名称, 一般就写 方法名、这个动作的名称。

  • class: 配置关联的action类的全限定名

  • method: action类中的方法名称,访问此action时调用的action类中的方法

    •   

      如果namespace值是/, 通过localhost:8080/项目名/add来访问
      如果namespace值是/user, 通过localhost:8080/项目名/user/add来访问
      好处: 在写请求路径的时候,意思更加明确,看路径就可以确定对应是哪个模块

3.Result标签

3.1概述

​ result标签用于返回action处理请求的结果。 一般可以跳转jsp页面也可以再跳转到其他的action。

3.2属性解释
  • name: 视图名字,对应的是Action类中执行的方法的返回值。

  • type: 响应给浏览器的类型.(默认是转发到页面)

四,Action进阶

1,Action规范和特点

1.1Action的编写规范
  1. action类需要提供无参构造函数

  2. action中方法规定

    ​ 修饰符:方法的修饰符必须是public

    ​ 参数列表:方法必须是无参方法

    ​ 返回值类型:String(目的在于响应)

1.2.action多例性【重点】

​ 每次url访问时,action的实例就会被创建一次。action类是多实例的。

2.Action的通用写法

2.1普通类

​ 这种方式就是我们最开始给大家写的, 就是一个普通类,然后里面写一个方法,具有String类型返回值即可。

2.2实现Action接口
  • 好处是 : 我们少写一点代码, 可以使用接口里面定义的常量 SUCCESS \ ERROR ....

 public class HelloWorld02 implements Action{
     @Override
     public String execute() throws Exception {
         System.out.println("hi struts");
         return SUCCESS;
     }
 }
2.3继承ActionSupport【重点】

​ 这种做法,相比较前面的好处在于, ActionSupport 虽然是实现了Action的接口 , 但是内部自己也扩展了些功能 :eg: 提供了信息的校验、并且能够根据校验的结果回到原来的页面。如 : 它里面也集成了获取国际化资源的方法,我们可以直接使用。

  • Java代码

    •   

       public class ActionDemo03 extends ActionSupport {
           @Override
           public String execute() throws Exception {
               System.out.println("ActionDemo03 execute()...");
               return SUCCESS;
           }
       }

3.Action访问的路径配置

3.1通过method属性访问【重点】

​ 一般来讲,我们的action类都不会只有一个execute方法,如果存在很多的方法 ,我们如何在struts.xml 里面映射到方法里面去呢? struts提供的第一种方法是在action里面使用method属性来指定访问的具体的方法。 举例如下:

<action name="user_login" class="demo.web.UserAction" method="login"></action>
<action name="user_regist" class="demo.web.UserAction" method="regist"></action>
<action name="user_active" class="demo.web.UserAction" method="active"></action>
<action name="user_loginout" class="demo.web.UserAction" method="logout"></action>

这样看上去是挺好的。 直接指定method ,就会找到具体的方法。 但是如果以后我们的方法很多,这样就要配置很多的action标签了。这就不太好维护了。代码先就显得很多,所以这种方式用的不多.

3.2通过通配符访问【重点】

​ 通配符的访问其实还是要依赖于method的属性,只不过在匹配来访的地址 和 action的名称的时候使用通配符来匹配。采取method属性访问的方式,一个请求需要写一个Action, eg:

<action name="user_login" class="demo.web.UserAction" method="login"></action>
<action name="user_regist" class="demo.web.UserAction" method="regist"></action>
<action name="user_active" class="demo.web.UserAction" method="active"></action>
<action name="user_loginout" class="demo.web.UserAction" method="logout"></action>

如果采取通配符的方式,只需要配置一个Action就可以了, *用于表示匹配任意字符。 后面的{1} 就表示能够取到 * 所处位置的字符,然后找到对应的方法。

<action name="user_*" class="demo.web.UserAction"  method="{1}"></action>

我们在开发中通常采取通配符方式访问.

3.3通过动态方法访问【了解】

​ 第三种方式可读性不强 ,这种方式使用动态代理访问。用的很少. 使用步骤:

  1. 打开动态访问开关,在Struts.xml文件配置

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

    2.配置Action的名字

<action name="userAction" class="com.itheima.web.UserAction"></action>

    3.访问路径通过actionName + !+ action类中的方法名访问

http://localhost:8080/Struts2/userAction!login

五.Result结果配置

1.全局和局部结果

​ 平常我们设置跳转页面,是在action标签里面加上 result标签来控制,这种设置的页面跳转,称之为 局部结果页面但是我们有时候在很多个action里面,针对不同的结果进行跳转时,也有可能跳转同一个页面,那么这个时候就可以配置全局结果页面。

1.1局部结果
  • 在action里面写上的result跳转的页面,称之为局部结果页面配置

<action name="demo01_*" class="demo.web.action.ActionDemo01" method="{1}">
     <result name="error">/error.jsp</result>
</action>
2全局结果
  • 如果有多个action的结果跳转的页面是一样的,那么我们可以提取出来,做成全局结果页面的配置. 全局页面通过package标签中配置global-results标签来定义

<package name="test" extends="struts-default" namespace="/">
    <global-results>
        <result name="error">/error.jsp</result>
    </global-results>
      ....
</package>

2.结果的类型(页面的跳转)

​ 根据前面学的servlet知识,我们知道服务器响应给浏览器的时候,有三种类型:response响应JSON数据&请求转发 & 重定向。 对于Struts2而言,无非就是Action跳转到页面,Action跳转到Action....

2.1Action跳转页面
  • 转发(默认)

<result name="success" type="dispatcher">/index.jsp</result>
  • 重定向
<result name="success" type="redirect">/index.jsp</result>
2.2Action跳转Action
  • 转发

<action name="demo01_*" class="demo.web.action.ActionDemo01" method="{1}">
        <result name="success" type="chain">demo02_fun02</result>
</action>
<action name="demo02_*" class="demo.web.action.ActionDemo02" method="{1}">
</action>
  • 重定向
<action name="demo01_*" class="demo.web.action.ActionDemo01" method="{1}">
        <result name="success" type="redirectAction">demo02_fun02</result>
</action>
<action name="demo02_*" class="demo.web.action.ActionDemo02" method="{1}">
</action>
2.3其它的结果

​ 一般来说,我们平常的请求到来,我们要不就是跳转到 页面上 ,要不就是跳转到下一个action 去。 但是除了这两种结果之外,我们仍然还有一些其他结果类型可以控制.

​ 比如: 我们可以返回一个文件数据给客户端 (比如文件下载).再比如: 我们可以返回一个json字符串给来请求的页面,而不是重新打开新的页面 (有点像之前的Ajax请求,返回json数据)

2.3.1响应JSON数据
  • 导入struts-json-plugin-xxx.jar

  • Java代码

public class ActionDemo01 extends ActionSupport {
    private User json;

    public User getJson() {
        return json;
    }

    public String fun01(){
        json = new User();
        json.setName("张三");
        json.setAge(18);
        json.setPassword("123456");

        return "success";
    }

}
  • 配置文件
<struts>
    <package name="test" extends="json-default" namespace="/">
        <action name="demo01" class="demo.web.action.ActionDemo01" method="fun01">
            <result name="success" type="json">
                 <param name="root">json</param><!--这里的name必须是root  至于这个json 是我们在action里面的成员 变量 json  -->
             </result>
        </action>
    </package>
</struts>

注意:

​ root:配置对象。action类中必须提供一个和root值相同的属性名称,且需要提供getter方法。

​ package需要继承json-default

​ result的type值是json

六,Struts2中的Servlet的API的访问

​ 客户端与服务端交互时,通常会带参数过来,服务器也会回写数据给客户端。在此过程中,参与着请求,和响应,以及会话。servlet在此过程中提供了HttpServletRequest作为获取请求数据的方案,HttpServletResponse作为响应的方案,HttpSession负责了会话方案。Struts其实是基于servlet实现的web框架,他需要遵循规则提供请求,响应和会话的API供开发人员使用,因此Struts针对这一问题提供了自己的一套API封装,提供了多种方式的访问。

1.ActionContext

1.1概述

​ ActionContext是Action的上下文,Struts2自动在其中保存了一些在Action执行过程中所需的对象,比如session, parameters等。Struts2会根据每个执行HTTP请求的线程来创建对应的ActionContext,即一个线程有一个唯一的ActionContext。

1.2使用
  • 获得(创建)ActionContext

     ActionContext context = ActionContext.getContext(); 

  • 获得请求参数

     Map<String, Object> parameters = context.getParamters(); 

    相当于Servlet中的request.getParamters()方法,只能获得所有的请求参数

2.ServletActionContext

2.1概述

​ ServletActionContext继承子ActionContext,因此比ActionContext功能要强大。ServletActionContext提供了多个静态方法。

2.2使用
  • 获得Request对象

HttpServletRequest request = ServletActionContext.getRequest();

  • 获得Response对象

HttpServletResponse response = ServletActionContext.getResponse();

  • 获得ServletContext

ServletContext servletContext = ServletActionContext.getServletContext();

3.实现接口的方式

  • 编写Action,让Action使用实现特定的接口的方式访问Servlet的API,有如下接口可以实现

    ​ ServletContextAware

    ​ ServletRequestAware

    ​ ServletResponseAware

    ​ SessionAware

    ​ ApplicationAware

  • Eg:

    public class ActionDemo03 extends ActionSupport implements ServletRequestAware {
        private HttpServletRequest request;
        public String fun03() throws IOException{
            HttpServletRequest request = ServletActionContext.getRequest();
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            System.out.println(username+":"+password);
            return NONE;
        }
        @Override
        public void setServletRequest(HttpServletRequest request) {
            this.request = request;
        }
    }

七,获得请求参数

1.获得零散数据

1.1使用上面介绍的Struts2中的Servlet的API获取
  • ActionContext

//1.创建ActionContext对象
ActionContext context = ActionContext.getContext();
//2.获得所有的请求参数
Map<String, Object> parameters = context.getParamters();
  • ServletActionContext

//1.获得request对象
HttpServletRequest request = ServletActionContext.getRequest();
requet.getParameter(String key);
requet.getParameterValues(String key);
requet.getParameterMap();
1.2静态参数
  • 页面

<h1>01使用静态属性</h1>
<form method="post" action="${pageContext.request.contextPath }/demo01">
    用户名:<input type="text" name="username"/><br/>
    密    码:<input type="password" name="password"/><br/>
    <input type="submit"/>
</form>
  • Action.java

public class ActionDemo01 extends ActionSupport {
    private String username;//和表单里面的name属性值要一致,并且提供set方法
    private String password;//和表单里面的name属性值要一致,并且提供set方法
    public void setUsername(String username) {
        this.username = username;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
    public String fun01(){
        System.out.println(username+":"+password);
        return NONE;
    }
}

2.获得封装后的数据(对象)

2.1属性驱动
  • 页面

<h1>01使用属性驱动方式</h1>
<form method="post" action="${pageContext.request.contextPath }/demo01">
    用户名:<input type="text" name="user.username"/><br/>
    密    码:<input type="password" name="user.password"/><br/>
    <input type="submit"/>
</form>
  • Action.java

public class ActionDemo01 extends ActionSupport {
    //1. User类里面的字段属性需要和表单里面的name属性一致, 且提供无参构造
    //2. user需要set和get方法
    private User user;
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
​
    public String fun01(){
        System.out.println(user.toString());
        return NONE;
    }
}
2.2模型驱动【重点】
  • 页面

<h1>02使用模型驱动方式</h1>
<form method="post" action="${pageContext.request.contextPath }/demo02">
    用户名:<input type="text" name="username"/><br/>
    密    码:<input type="password" name="password"/><br/>
    <input type="submit"/>
</form>
  • Action.java

public class ActionDemo02 extends ActionSupport implements ModelDriven<User> {

    private User user;

    public String fun02(){
        System.out.println(user.toString());
        return NONE;
    }
    @Override
    public User getModel() {
        if(user == null){
            user = new User();
        }
        return user;
    }
}
2.3封装到集合

​ 封装到集合,一般我们会在批量添加 、批量更新场景下见到。也就是说页面上同一个请求,这时候提交过来多份数据,如果我们是批量添加用户的话,可能会提交过来多个用户,那么这个时候,我们就需要把他们封装到List集合或者Map集合中去。 刨去批量操作、我们比较少用这种封装到集合的知识点。

2.3.1封装到list
  • 页面

<h1>01封装到list</h1>
<form method="post" action="${pageContext.request.contextPath }/demo01">
    用户名:<input type="text" name="list[0].username"/><br/>
    密    码:<input type="password" name="list[0].password"/><br/>
    用户名:<input type="text" name="list[1].username"/><br/>
    密    码:<input type="password" name="list[1].password"/><br/>
    <input type="submit"/>
</form>
  • Action.java

public class ActionDemo01 extends ActionSupport {

    private List<User> list;

    public List<User> getList() {
        return list;
    }
​
    public void setList(List<User> list) {
        this.list = list;
    }
​
    public String fun01(){
        System.out.println(list.toString());
        return NONE;
    }
}
2.3.2封装到Map
  • 页面

<h1>02封装到map</h1>
<form method="post" action="${pageContext.request.contextPath }/demo02">
    用户名:<input type="text" name="map['user1'].username"/><br/>
    密    码:<input type="password" name="map['user1'].password"/><br/>
    用户名:<input type="text" name="map['user2'].username"/><br/>
    密    码:<input type="password" name="map['user2'].password"/><br/>
    <input type="submit"/>
</form>
  • Action.java

public class ActionDemo02 extends ActionSupport {

    private Map<String, User> map;

    public Map<String, User> getMap() {
        return map;
    }

    public void setMap(Map<String, User> map) {
        this.map = map;
    }

    public String fun02(){
        Set<Entry<String, User>> entrySet = map.entrySet();
        for (Entry<String, User> entry : entrySet) {
            System.out.println(entry.getKey()+":"+entry.getValue().toString());
        }
        return NONE;
    }

最新文章

  1. 开发一款完备的android应用所必备的知识
  2. [代码片段]javascript检查图片大小和格式
  3. MATLAB 利用filter函数实现滑动平均滤波
  4. What is the difference between Views and Materialized Views in Oracle?
  5. iOS 面试基础题
  6. c# 关于10进制和16进制转换以及显示
  7. AngularJs ui-router 路由的介绍
  8. [BZOJ3668] [Noi2014] 起床困难综合症 (贪心)
  9. 计算机网络之IP地址
  10. 边缘计算在物联网(IoT)当中的运用「物联网架构探索系列」
  11. python添加、修改、删除、访问类对象属性的2种方法
  12. ORACLE数据库测试数据插入速度[z]
  13. 集合类--最详细的面试宝典--看这篇就够用了(java 1.8)
  14. #ifndef HeaderName_h #define HeaderName_h #endif 使用详解
  15. Software development skills for data scientists
  16. PHP和mysql英文
  17. 基础知识系列☞C#中→委托
  18. Majority Number III
  19. Smack 广播
  20. Java 多线程通信之多生产者/多消费者

热门文章

  1. Django学习-19-缓存
  2. pat1071-1080
  3. CF368 E - Garlands
  4. word文档的动态添加数据
  5. ASP.NET 初识Cookie
  6. 主流nosql数据库对比
  7. 【BZOJ3436】小K的农场(差分约束)
  8. [BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化)
  9. jdk,maven,tomcat 的环境配置
  10. Python多线程爬虫与多种数据存储方式实现(Python爬虫实战2)