Java学习之struts2使用


Java学习之struts2使用

0x00 前言

持续记录学习内容

0x01 struts2 使用

  1. 导入ja包


org.apache.struts
struts2-core
2.5.13


  1. web.xml配置
<!--Struts2核心过滤器-->

Struts2
org.apache.struts2.dispatcher.filter.StrutsPrepareAndExe cuteFilter


Struts2
/*

  1. Action类
package action;

import com.opensymphony.xwork2.Action;

public class HelloWorldAction implements Action{
    //请求中传递的参数和返回给页面的值都定义成属性
    private String username
    private String password  
//getter/setter方法
@Override
public String execute()throws Exception{
//查看请求中传递的参数
System.out.print1n(username);
//改变这个message,会自动传递给页面
    message="hello:"+username;
//SUCCESS是Action中的常量,值是success
    return SUCCESS;
}}
  1. struts.xml
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-/∥Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">

<.--所有的action都放在package中,必须继承struts-default-->
<!--struts-default中有默认的拦截器配置,能处理参数等信息-->
	
<!--name对应的是请求的地址,class是处理请求的类-->

<!--success是Action类中返回的字符串,根据不同字符串返回不同的页面-->
index.jsp

	

  1. 编写index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>



    Title
    


struts2

id: username:
${requestScope.message}

访问到http://127.0.0.1/hello.action时,则就映射到HelloWorldAction.execute方法里面,而这里的方法返回SUCCESS,struts2这样进行了配置


<!--success是Action类中返回的字符串,根据不同字符串返回不同的页面-->
index.jsp

index.jsp

则代表如果这个HelloWorldAction.execute方法返回的是success的话则映射到index.jsp文件中。

struts默认支持的请求后缀是.action,如果需要配置其它的后缀,需要在struts.xml中配置:

设置允许请求后缀为do和html


0x02 struts.xml详解

constant 标签

<!--设置请求后缀-->

<!--设置编码,解决中文乱码-->

<!--设置struts标签主题-->

constant用来配置常量。name属性是常量名,value属性是常量值。
constant常量可以改变Struts2的一些行为,比如U山标签的样式、编码格式等。
因为struts2默认的编码格式就是UTF-8,所以不用特意指定编码,中文也不会乱码。

package标签


package是包。Struts2的package与java中的package类似,可以把同一个业务模块的action和result集中到一个包中,方便管理。不同的是Struts2的包可以继承。比如商品有增删改查操作,订单也有增删该查操作,我们可以将商品和订单的action分别放两个package中方便管理。

name属性是包的名字,一个struts.xml中可以有很多个package,通过name属性进行区分。

namespace是命名空间,/代表的是根目录。namespace的作用类似于SpringMVC中在Controller类上加@RequestMapping注解。相当于此包中所有的action前都加一个父路径。如:



上面这个name=login的action,在访问的时候路径就是/user/login.action extends属性是继承,通常都会继承struts-default。在struts-default中定义了大量的struts特性,如拦截器和参数处理的功能,如果不继承struts-default,会遇到参数无法绑定或找不到action类。

action标签


<--success是Action类中返回的字符串,根据不同字符串返回不同的页面-->
index.jsp
error.jsp1ogin.jsp

action标签用来处理请求和响应结果。
name属性是请求的名字,此处不需要加.action。同一个package下的action不能重名。
class属性指定处理该请求的类,是类的全路径。默认的处理请求时会去类中找名为execute的方法。如果不指定class,将默认ActionSupport为处理请求的类。
result标签用来处理请求结果,name属性是Action类中返回的字符串。标签的值是要跳转的页面地址。name如果不写的话,默认是success。

0x03 Action配置

Struts2的主要核心是Action类。

import com.opensymphony.xwork2.Action;public class HelloWorldAction implements Action{
//请求中传递的参数和返回给页面的值都定义成属性

    private String username;
     private String message;
   //getter/setter方法
@0verride
    public String execute()throws Exception{
//查看请求中传递的参数
System.out.println(username);
        
      
        
        //改变这个message,会自动传递给页面	
        message="hello:"+username;
//SUCCESS是Action中的常量,值是success 
            return SUCCESS;

一个Action业务里可以实现Action接口,也可以继承ActionSupport类。在ActionSupport中提供了一些实现好的业务方法。在以后的编程中,建议全部继承ActionSupport类。
Action中的方法必须返回一个String类型的字符串,这个字符串与struts.xml中result标签的name属性相对应,struts.xml会根据返回的字符串查找对应的页面。
在Action接口中提供了5个常用的结果常量:

package com.opensymphony.xwork2;

public interface Action {
    String SUCCESS = "success";
    String NONE = "none";
    String ERROR = "error";
    String INPUT = "input";
    String LOGIN = "login";

    String execute() throws Exception;
}

自定义业务

在前面的学习中,Action类中只有一个execute方法。
假如用户有注册和登录两个功能,我们可以把这两个功能写进同一个Action类:

package action;import com.opensymphony.xwork2.ActionSupport;
/∥继承ActionSupport类
public class UserAction extends ActionSupport{
//处理登录
public String 1ogin(){
//参数和业务略
System.out.println("我是登录");
    return SUCCESS;
//处理注册
public String regist(){
//参数和业务略
System.out.println("我是注册");
        return SUCCESS;
}

注意所有处理请求的业务方法必须是public的,而且要返回一个String。struts.xml中配置:


<!-一通过method指定调用类中的哪个方法-->

index.jsp<!--登录成功去首页-->
1ogin.jsp<!--登录失败回登录页-->


index.jsp<!--注册成功去首页-->
regist.jsp<!--注册失败回登录页-->


method="login"表示要调用类中的login方法处理请求。如果找不到login0方法,Struts2会在类中查找doLogin)方法。如果都找不到,将会报错。

动态方法调用

如果一个类中有多个业务方法,又不想给每个业务方法都配置一个action标签,可以使用动态党法调用,语法是:请求名!方法名.action当请求的格式是user!login.action时,代表调用UserAction中的login)方法处理当前请求。当请求的格式是user.regist.action时,代表调用UserAction中的regist)方法处理当前请求。

<!--允许调用动态方法-->

action配置

<!--允许动态调用的方法,新版里新增的设置-->
1ogin,regist

/index.jsp<!--成功去首页-->
/error.jsp<!--失败去错误-->

通配符使用

login,regist

/index.jsp
{1}.jsp<!--失败了就返回原来的页面-->

User匹配所有以User结尾的请求,method={1}中的{1}匹配的就是 User中的。如果请求的地址是loginUser.action,那么{1}匹配的就是login,就会去类中调用login方法,并返回相应的结果。

默认Action

如果在struts.xml中找不到匹配的action,将会报错。可以设置一个默认的action。当所有请求都不匹配时,将匹配默认action。



error.jsp

对当前的package有效。
action标签的clas省略将调用ActionSupport类。result的name省略将默认为success。
注意default-action-re必须在所有的action标签上面。

Result 配置

常用结果有三种类型:dispatcher、redirect、redirectAction、chain

dispatcher

result的默认类型就是dispatcher。以下两个标签是等价的:
dispatcher的结果等同于Servlet中的请求转发,即:
request.getRequestDispatcher("success.jsp").forward(request,response);请求转发的意思是当前请求中的参数、属性在下一个页面或请求中仍然可
以使用。

index.jsp
index.jsp

redirect

redirect是重定向,重定向之后,当前请求中的参数和属性在下一个页面或请求中将不能使用。

index.jsp

相当于Servlet中的:response.sendRedirect("success.jsp");

redirectAction

redirectAction与redirect类似,不过redirectAction是重定向到某一个action


1ogin.action
regist.jsp

如果要调用不同package下的action,需要在result中传参数:



<!--调用不同package下的action-->
/
hel1o.action
<!--传递其它参数-->
123

    login.jsp

chain

redirectAction不能共享request中的数据,如果想共享数据,可以将type设置为chain。


<!--注意chain的action后面没有后缀-->
login
regist.jsp

动态获取结果

private String username;private String page;
//getter/setter方法略
public String 1ogin(){
//参数和业务略
System.out.print1n(“我是登录");if("admin".equals(username)){//管理员去管理页page="admin-page";
    }else{//其他人去用户页page="user-page";return SUCCESS;
}

result配置


<!--读取action中的属性值,返回不同页面-->
${page}.jsp
login.jsp

访问Servlet

Struts2访问Servlet API有解耦和耦合两种方式

解耦方式

Struts2将部分Servlet APl中的对象封装成Map,可以通过ActionContext获取。获取到的Servlet API对象全部是Map

public String regist(){
ActionContext ac=ActionContext.getContext();
    Map request=(Map)ac.get("request"); //获取request
    Map session=ac.getSession(); //获取session Map 
   	application=ac.getApplication();
    //获取application 
    session.put("session_user",“123");
        //向session中存值
        return SUCCESS;

需要注意的是Session和Application都有对应的get方法,而request没有,需要使用get("request")获取。
页面上可以使用

${sessionScope.session_id}
取值

解耦方式

该方式需要导入jar包


javax.servlet
servlet-api
2.5

HttpServletRequest request=
ServletActionContext. getRequest();

HttpSession session=request.getSession(); HttpServletResponse response=
ServletActionContext.getResponse();

0x03 struts 标签





如果想使用原始的样式可以配置struts.xml


通用标签




si标签用于条件判断,相当于jstl中的


s:elseif和s:else标签必须与s:if结合使用。


s:iterator用于集合的遍历,相当于jstl中的

0x04 数据校验

通用校验

Action类继承ActionSupport,ActionSupport中有一个validate方法进行数据校验,只需要重写该方法即可实现数据校验功能。

package action;

import com.opensymphony.xwork2.ActionSupport;

public class ValidateAction extends ActionSupport {
    private String username;//用户名不能为空,并且长度要大于6

    @Override
    public void validate() {
        System.out.println("validate()");
        if (username == null || username.trim().length() < 6) {
            addFieldError("username", "必须输入用户名,长度大于6");
        }
    }

    public void validateLogin() {
        System.out.println("validateLogin() ");
        if (username == null || username.trim().length() < 6) {
            addFieldError("username", "xxx");
        }
    }

    public String login() {
        System.out.println("登陆");
        return SUCCESS;
    }

    public String regist() {
        System.out.println("注册");
        return SUCCESS;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

addFieldError要求必须给result配置一个input类型的结果。所以在调用logout方法时,会报找不到result input。

        
            main.jsp
            val.jsp
        

方法校验

validate方法会验证当前Action类中所有的方法,如果只想验证其中的一个方法,可以使用validatexxx方法,其中xxx是被验证的方法名,首字母大写。

//只验证1ogin方法,不验证其它方法
public void validatelogin(){
if(username==nul1 ll username.1ength()==0){
//向页面中添加错误信息
addFieldError("username",“用户名不能为空”);

校验框架

验证框架是把验证信息都写在xm文件中,对某一个Action类进行验证,需要在Action类的同一个包下创建xml文件,文件命名为Action类的类名validation.xml

<?xml version="1.0" encoding="UTF-8"?>




    
        
            必须输入用户名
        
        
            6
            长度必须大于${minLength}
        
    

validators标签:在校验框架中,所有的验证都写在validators标签中field标签:每一个需要验证的属性都是一个field标签,name指定要验证那个属性。
field-validator标签:代表一种验证规则,通过type指定规则。

0x05 拦截器

拦截器可以在请求进入action之前做预处理,比如判断用户是否登录。也可以在action执行之后进行处理。和filter比较像,但是filter是基于函数回调,而拦截器是基于反射去实现。

创建一个类需要实现Interceptor接口

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class TimeInterceptor implements Interceptor {

    @Override
    public void destroy() {

    }

    @Override
    public void init() {

    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        long start = System.currentTimeMillis();
        String result = actionInvocation.invoke();//将请求放行,进入action
        long end = System.currentTimeMillis();
        System.out.println("运行时间:" + (end - start));
        return result;
    }

在struts.xml中配置拦截器


        

            
            
            
                
                
                
            
        
        
            /login.jsp
        

注意配置位置

在需要拦截的Action中添加拦截器的引用



index.jsp

这时候去访问hell.action就可以进入到拦截器了。

使用自定义拦截器会造成参数无法读取,这时候可以引入struts自带的拦截器。


拦截器栈




<!--拦截器栈,多个拦截器捆绑在一起执行-->






将多个拦截器绑定到一起,只需要引用拦截器栈即可。

登录拦截

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

import java.util.Map;

public class LoginInterceptor implements Interceptor {
    @Override
    public void destroy() {

    }

    @Override
    public void init() {

    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        ActionContext actionContext = ActionContext.getContext();
        Map session = actionContext.getSession();
        if(session.get("SEEION_USER")==null){//没有登陆
            return "login";
        }
        return actionInvocation.invoke();
    }
}

0x06 JSON

导入依赖

  

            org.apache.struts

            struts2-json-plugin

            2.5.13

        

Action类:

public class JsonAction extends ActionSupport {

    private Map resultMap;

    @Override
    public String execute() throws Exception {
        resultMap = new HashMap<>();
        resultMap.put("key1", "abc");
        resultMap.put("key2", 123);
        return "success";
    }

    public Map getResultMap() {
        return resultMap;
    }

    public void setResultMap(Map resultMap) {
        this.resultMap = resultMap;
    }
}



resultMap

这个包必须继承json-default

0x07 文件上传

public class FileAction extends ActionSupport {
    private File upload;
    private String uploadFileName;

    public String upload() {
        System.out.println(uploadFileName);
        try {
            String ext=uploadFileName.substring(uploadFileName.lastIndexOf("."));
            byte[] buffer = new byte[1024];
            FileInputStream fis = new FileInputStream(upload);
            FileOutputStream fos = new FileOutputStream("d:/upload/" + System.currentTimeMillis()+ext);
            int len = fis.read(buffer);
            while (len != -1) {
                fos.write(buffer);
                len = fis.read(buffer);
            }
            fos.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SUCCESS;
    }

Action代码中的upload与页面表单中的upload相对应。使用xxFileName封装文件名,其中的xx指代File变量的名字。

Struts.xml配置

        
            /upload.jsp
        

上传页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>



    Title
    



下载

0x08 结尾

冲冲冲!!!