首页 > 程序开发 > 软件开发 > Java >

JavaWeb深入分析之Struts2开发核心之动作类Action

2017-11-03

JavaWeb深入分析之Struts2开发核心之动作类Action。

一、Action动作类(一般用**Action结尾)

struts2 的Action可以是POJO(Plain Old Java Object)
为了让用户开发的Action更加规范struts2提供了一个Action接口

这里写图片描述

通过method属性指定Action执行方法

没有指定method属性,默认执行execute方法

通过method属性,指定调用Action相应方法处理请求

因为指定了method=”add”,所以HelloAction的ass方法会被调用.

1、编写动作类的三种方式

a、第一种方法是,动作类不实现、也不继承任何的接口和类。即动作类是一个非常普通的JavaBean。

public class HelloAction {
    public String sayHello(){
        System.out.println("动作类执行了,访问成功!");
        return "success";
    }
} 

b、动作类实现com.opensymphony.xwork2.Action接口。可以使用常量

Action接口:

public static final String SUCCESS = "success"; //成功时转向的视图
public static final String NONE = "none";//执行成功后,不转向的任何视图。比如下载任务
public static final String ERROR = "error";//转向错误视图
public static final String INPUT = "input";//转向输入视图。(回显:验证与转换失败,转向原有页面)
public static final String LOGIN = "login";//登录视图(用户没有登录)
public String execute() throws Exception;// public 修饰符,String 返回值,无参数

c、继承com.opensymphony.xwork2.ActionSupport(开发中建议)

Struts2为Action接口提供了一个实现类 ActionSupport,定义了 表单域校验、错误信息设置和获得国际化信息相关一些方法

public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {

    protected static Logger LOG = LoggerFactory.getLogger(ActionSupport.class);

    private final ValidationAwareSupport validationAware = new ValidationAwareSupport();

    private transient TextProvider textProvider;
    private Container container;

    public void setActionErrors(Collection errorMessages) {
        validationAware.setActionErrors(errorMessages);
    }

    public Collection getActionErrors() {
        return validationAware.getActionErrors();
    }

    public void setActionMessages(Collection messages) {
        validationAware.setActionMessages(messages);
    }

    public Collection getActionMessages() {
        return validationAware.getActionMessages();
    }

2、动作类中的动作方法

要求:
a、必须是public的
b、必须返回String类型的
c、必须没有参数

3.动作类的生命周期

动作类每次访问都会重新被实例化,是线程安全的。

public class HelloAction {

    public HelloAction() {
        System.out.println("执行构造函数HelloAction,实例化对象。");
    }

    public String sayHello(){
        System.out.println("动作方法sayHello执行了,访问成功!");
        return "success";
    }
}

测试结果:

这里写图片描述

二、动作类中动作方法的调用

动作方法:动作类中的定义的处理业务有关的方法

实例:模拟一个curd的动作类

工程目录如下:

这里写图片描述

1、新建一个 curd.jsp

  
    增加用户
    修改用户
    查询用户
    删除用户
  

2、在struts.xml中配置

如下图所示:

这里写图片描述


    
    
         
            /addCustomer.jsp
            /error.jsp
        
         
            /editCustomer.jsp
        
         
            /findCustomer.jsp
        
         
            /delCustomer.jsp
        
    

3、建立动作处理类CustomerAction

package xgp.struts.actions;

import xgp.struts.service.BusinessService;
import xgp.struts.serviceImpl.BusinessServiceImpl;

import com.opensymphony.xwork2.ActionSupport;

public class CustomerAction extends ActionSupport{

    private BusinessService bs = new BusinessServiceImpl();
    public String add(){
        //调用Service添加方法
        try {
            bs.add();
            return SUCCESS;
        } catch (Exception e) {
            return ERROR;
        }
    }

    public String edit(){
        bs.edit();
        return SUCCESS;
    }

    public String find(){
        bs.find();
        return SUCCESS;
    }

    public String del(){
        bs.del();
        return SUCCESS;
    }
}

4、建立相应的业务接口BusinessService和实现类BusinessServiceImpl
BusinessService

package xgp.struts.service;

public interface BusinessService {
    public void add();
    public void edit();
    public void del();
    public Object find();

}

BusinessServiceImpl

package xgp.struts.serviceImpl;

import xgp.struts.service.BusinessService;

public class BusinessServiceImpl implements BusinessService{

    @Override
    public void add() {
        System.out.println("Serviece的add方法执行成功!");

    }

    @Override
    public void edit() {
        System.out.println("Serviece的edit方法执行成功!");

    }

    @Override
    public void del() {
        System.out.println("Serviece的del方法执行成功!");

    }

    @Override
    public Object find() {
        System.out.println("Serviece的find方法执行成功!");
        return null;
    }

}

结果如下:

这里写图片描述

1、使用通配符配置Action

在配置元素时,允许在指定name属性时,使用模式字符串(用"*"代表一个或多个任意字符)

在class、method属性及子元素中通过 {N} 形式代表前面地N个* 匹配子串

这里写图片描述

例如上面的案例中struts.xml我们可以改写如下:



          
 
    /{1}{2}.jsp

2、使用Action的动态方法调用(官方不建议使用)

动态方法调用:DMI
http://localhost:8080/xgp.struts/customer/add_Customer!add

希望执行CustomerAction的add动作方法(动态方法调用)
动态方法调用:Struts2框架默认是禁止的。可以通过配置一个常量打开它:

通过url动态指定调用Action哪个方法而无需配置的method属性, 通过 !方法名 指定调用Action哪个方法

添加用户

修改用户

删除用户

3、配置默认Action和 配置Action默认处理类

用户可以为每个package定义一个默认的Action,如果访问路径在package没有匹配 就会执行默认action


 
    /whatareuwant.jsp

如果配置 没有指定class属性,就会执行Action的默认处理类,在struts-default.xml中.
指定默认的动作处理类

 
        
        
         
         
            /success.jsp
        
         
            /whatareuwant.jsp
        

三、在动作类中访问ServletAPI

Struts2的Action没有与任何Servlet API耦合,便于测试.这是他的优点之一.

1、三大实现方法

1、ActionContext

getContext() 返回ActionContext实例对象 get(key) 相当于 HttpServletRequest的getAttribute(String name)方法 put(String,Object) 相当于HttpServletRequest的setAttribute方法 getApplication() 返回一个Map对象,存取ServletContext属性 getSession() 返回一个Map对象,存取HttpSession属性 getParameters() 类似调用HttpServletRequest的getParameterMap()方法 setApplication(Map) 将该Map实例里key-value保存为ServletContext的属性名、属性值 setSession(Map) 将该Map实例里key-value保持为HttpSession的属性名、属性值

2、方式二:(简单,推荐使用)使用ServletActionContext

static PageContext getPageContext()
static HttpServletRequest getRequest()
static HttpServletResponse getResponse()
static ServletContext getServletContext()

该方案可避免Action类实现XxxAware接口,但Action依然与Servlet API直接耦合
开发中优先使用ActionContext 这样可以避免耦合

package com.itheima.actions;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;

import com.opensymphony.xwork2.ActionSupport;

public class ServletAPIAction1 extends ActionSupport{

    //打印当前应用名称到控制台上
    //获取ServletAPI有关类的实例
    //方式一:
    public String execute() throws Exception {
        //实际上利用ThreadLocal这个类
        //ServletActionContext:记住
        HttpServletRequest request = ServletActionContext.getRequest();
        System.out.println(request.getContextPath());
        PageContext pc = ServletActionContext.getPageContext();
        HttpServletResponse response = ServletActionContext.getResponse();
        response.getWriter().write(request.getContextPath());//自己输出
        ServletContext sc = ServletActionContext.getServletContext();
        System.out.println(sc.getRealPath("/"));
        return NONE;
    }
}

3、方式三:(麻烦)实现接口,访问Action时完成注入

ServletContextAware
void setServletContext(javax.servlet.ServletContext context)

ServletRequestAware
void setServletRequest(javax.servlet.http.HttpServletRequest request)

ServletResponseAware
void setServletResponse(javax.servlet.http.HttpServletResponse response)

动作类实现特定的接口。就必须实现特定的方法,调用动作方法前,框架会把响应的对象给注入进来。

package com.itheima.actions;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;

import com.opensymphony.xwork2.ActionSupport;
//获取ServletAPI有关类实例的方式二
public class ServletAPIAction2 extends ActionSupport implements ServletRequestAware,ServletResponseAware{
    private HttpServletRequest request;
    private HttpServletResponse response;
    //该方法会在调用动作方法之前先执行:把当前的HttpServletRequest对象给你注入进来
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }
    @Override
    public String execute() throws Exception{

        //要使用HttpServletRequest对象
        //System.out.println(request.getContextPath());
        response.getWriter().write(request.getContextPath());
        return NONE;
    }
}

原理:是一个拦截器给你注入进来的。struts-default.xml

<interceptor name="servletConfi


一看源码便知。
配置struts.xml:



 
 

    
    
        
 
        
         
            /success.jsp
        
         
            /success.jsp
        
    

2、局部和全局结果视图

result元素:指定动作类的动作方法执行完后的结果视图.
属性:
- name:字符串,与动作方法返回的值一致。默认是success
- type:指定处理结果的结果类型的别名。(struts-default.xml有定义,共10个)。默认值是dispatcher

Action处理完用户请求后,将返回一个普通字符串整个普通字符串就是一个逻辑视图名,Struts2 根据逻辑视图名,决定响应哪个结果。

Struts2处理结果使用元素配置

局部结果:将作为子元素配置 全局结果:将作为元素的子元素配置

配置元素通常需要指定两个属性

name 该属性指定配置逻辑视图名 type 该属性指定结果类型

当多个action中都使用到了相同result,这时我们应该把result定义为全局结果。struts1中提供了全局forward,struts2中也提供了相似功能:



    
        /message.jsp
    

注:局部的会覆盖全局

Struts1中应用范围内action的实例 action是单实例(执行时,现在缓存中查找实例,有用,没有创建新的实例)Struts2中 应用范围内action的实例,每个请求都会创建一个action实例Servlet属于单实例多线程的应用,实例只在初始化时被加载多实例比单实例的优点,不会产生并发问题,但执行速度不如单实例

如下:



    
 
        
            
                /success.jsp
            
        
 
        
         
            
        
         
            
        
    
 
    
             
                
            
    
 


这里写图片描述

3、Struts2提供的结果视图 (共10个)











1. chain:从一个动作转发到另外一个动作

同一个包内的动作转发


    
        
         
            action2
        
         
            /success.jsp
        
    

不同包之间的动作转发


    
          
            /user 给chain的实际处理类注入参数action2
            
        
    

2. dispatcher:从一个动作转发到另外一个JSP

dispatcher 结果类型是最常用的结果类型, 也是 struts 框架默认的结果类型
该结果类型有一个 location 参数, 它是一个默认参数

这里写图片描述

dispatcher 结果类型将把控制权转发给应用程序里的某个资源

3. redirect:从一个动作重定向到一个JSP
最明显的是地址栏发生变化。



    /success.jsp

4. redirectAction:从一个动作重定向到另外一个动作
action1先将动作重定向到action2,然后action2在转发到success.jsp,地址栏应该显示的是action2.



    action2

 
    /success.jsp

5. plainText:以纯文本的形式显示JSP



     
        /success.jsp
    

6. stream:文件下载



         
            
                imageInputStream
                application/octet-stream
                attachment;filename=26.jpg
                1024
            
        
    

DownLoadAction类


package com.itheima.actions;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import javax.servlet.ServletContext;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;
//文件下载;结果类型stream的使用
public class DownLoadAction extends ActionSupport {

    private InputStream imageInputStream;

    public InputStream getImageInputStream() {
        return imageInputStream;
    }

    public void setImageInputStream(InputStream imageInputStream) {
        this.imageInputStream = imageInputStream;
    }

    public String download() throws Exception{
        //得到文件的真实路径
        ServletContext sc = ServletActionContext.getServletContext();
        String filePath = sc.getRealPath("/WEB-INF/classes/26.jpg");
        //构建输入流
        imageInputStream = new FileInputStream(filePath);
        //用stream结果视图输出
        //返回逻辑视图
        return SUCCESS;
    }
}

结果显示

这里写图片描述

4、自定义结果视图

目标:用一个叫做image的视图,输入随机验证码图片 CAPTCHA,我们首先可以看dispatcher的声明;

public class org.apache.struts2.dispatcher.ServletDispatcherResult extends org.apache.struts2.dispatcher.StrutsResultSupport

public abstract class org.apache.struts2.dispatcher.StrutsResultSupport implements com.opensymphony.xwork2.Result

可以看到dispatch的实现类是继承StrutsResultSupport,而StrutsResultSupport又实现了Resul接口。多以我么可以

1、编写一个类实现com.opensymphony.xwork2.Result,或者继承org.apache.struts2.dispatcher.StrutsResultSupport,这里定义一个类,实现com.opensymphony.xwork2.Result接口


package xgp.struts.actions;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;


public class CaptchaResult implements Result {

    private int width;
    private int height;

    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public void execute(ActionInvocation arg0) throws Exception {
        /*int width=120,height=25;*/
        //1.在内存生成一个图片
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //2.得到画笔
        Graphics g = img.getGraphics();
        //3.画一个矩形框
        g.setColor(Color.BLUE);
        g.drawRect(0, 0, width, height);
        //4.填充背景
        g.setColor(Color.YELLOW);
        g.fillRect(1, 1, width-1, height-1);
        //5.画一些干扰线条
        g.setColor(Color.GRAY);
        Random random = new Random();
        for(int i=1;i<=20;i++)
             g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
        //6.画字符串随机的
        g.setColor(Color.RED);
        //设置字体
        g.setFont(new Font("宋体",Font.BOLD|Font.ITALIC,20));
        for(int i=1;i<=4;i++)
            g.drawString(random.nextInt(10)+"", i*20,20);



        //7.输出
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("image/jpeg");
        ImageIO.write(img, "jpg", response.getOutputStream());

    }

}

2、自定义的结果视图,(必须先声明后才能使用)



    
        
    
     
        300400
        
           

           

3、就可以使用了,编写视图页面login.jsp



    
用户名:
验证码:验证码加载中...

运行结果
这里写图片描述

如果想在多个包中用,可以将package声明为abstract ,然后别的包继承自这个包即可。

阶段性小结

这里写图片描述

相关文章
最新文章
热点推荐