struts2(自用)

一个基于请求的轻量级的mvc框架

struts2的helloworld案例

  1. 新建web项目
  2. 导入jar包
  3. 编辑web.xml文件–配置struts2的前段控制器(分发器)

在struts2中所有的业务方法都是public的,返回值都为String类型,所有的业务方法都没有参数,方法名可以自定义,默认为execute

struts2配置

web.xml
前端控制器
struts2框架开始工作的入口,接管请求

struts2.xml该配置文件名称固定,并且只能放于src下

package(重点):
	name自定义,但不能重复
	namespace命名空间和url直接相关
	如:/请求为/hello.action /user 请求为/user/hello.action
	extends 继承,必须直接或者间接继承struts-default
	action:
		name为请求名 不加后缀
		class 处理类的完全限定名称 包名+类名,如果不配置,有默认类来处理(ActionSupport)
		method 绑定方法名,指定处理请求的方法
		<result name=""></result>结果集配置
			name 结果集名称和处理方法的返回值匹配,默认为success
			Struts2提供了5个返回结果:
				Action.SUCCESS 执行成功,跳转到下一个试图 
				Actuon.NONE 执行成功,不需要视图显示
				Actuon.ERROR 执行失败,显示失败页面
	
				Actuon.INPUT  要执行该Action需要更多的输入条件
				Actuon.LOGIN 需要登陆后才能执行
			type 指定响应结果类型
				dispatchr 转发默认
				redirect 重定向
				redirectAction 重定向到Action
			result的值为跳转页面,如果不加/namespace路径,建议绝对路径
	

在package中可以配置全局的结果集

		<global-results>
			<result></result>
		</global-results>
constant(常量配置):
	name:
		struts.action.extension  扩展名
		struts.i18n.encoding 乱码
		struts.devMode  开发模式
	value:
		对应配置值
include:
	引入其它配置文件
	file="struts/configuration/system.xml"

配置优化

随着业务增加action配置文件会急剧增加,导致配置文件的膨胀问题。

  1. 动态方法调用来解决
    开启动态方法调用
<constant name="struts.enable.DynamicMethodInvocation"value="true" />

配置action,一个处理类只需配置一次,不需要配置处理方法。
调用处理方法:ActionName!methodName.action
注意:不同处理方法的返回值是否一致。会配置多个结果集。不推荐使用,不安全。
2. 通配符配置
在这里插入图片描述

  1. 注解
    导入jar包**struts2-convention-plugin**
    在处理类上填写相关注解
    在这里插入图片描述
    在这里插入图片描述

struts2的执行流程

  1. 发起请求
  2. 服务器接受请求并交给struts2的前端控制器web.xml(和filter-mapping url-pattern匹配)
  3. 根据请求的url查看strus.xml中的namespace+action是否存在,不存在404
  4. 存在,执行action所对行类的对应方法
  5. 根据方法的执行结果到action的结果集进行匹配
  6. 响应结果

数据处理

属性驱动

  1. 使用struts2获取表单域名称和action处理类的属性名称一致,并且提供属性的set方法,那么在action处理类中即可获得表单数据,称为属性驱动。
    驱动类

页面
2. 如果数据需要显示到页面上,那么数据可以做为处理类的属性,处理方法后该属性有值,并且有该属性的get方法。页面上可以通过el表达式获取
3.

对象驱动(重点)

在action的处理类中,属性以对象方式存在,该属性只需声明即可。需要保证该属性对象有无参构造函数(以反射创建对象),并且提供set,get方法。在表单域中的表单域名名称,以属性对象.属性对象的属性来命名
user类

action处理类

页面

模型驱动

在对象驱动中,页面的表单域名称复杂,通过模型驱动可以解决这个问题。
模型驱动需要处理类实现ModelDriven<对象>接口,并且主动将对象创建好
处理类

页面

action处理类的创建方式

  1. 通过实现Action接口(使用较少)
    实现Action接口的方式,可以直接使用Action提供的常量。
    必须重写默认处理方法(execute)
    处理类

  2. 通过继承ActionSupport来创建Action的处理类,struts2推荐方式
    实现了Action接口。
    并且提供了其他功能如:数据校验,国际化。

  3. 无侵入性实现
    灵活可以更换框架

ThreadLocal和ActionContext

ThreadLocal是一个容器,存放在该容器中的数据是线程安全的

	final ThreadLocal<Integer> th = new ThreadLocal<Integer>();
		th.set(23);
		new Thread() {
			public void run() {
				th.set(12);
				System.out.println(th.get());
			}
		}.start();
		System.out.println(th.get());
	}

ActionContext是struts2的上下文对象。本质是容器,一个map结构对象。线程安全的,贯穿整个Action的执行生命周期,每次接受请求都会重新建一个ActionContext对象,将servlet中的数据存入容器中,实现了struts2和servlet解耦。
ActionContext包含六个存储(request放HttpservletRequest域中的数据,session放HttpSession域中的事件,application放ServletContest域中事件,parameters放请求参数,attr放request,session,application中数据,ValueStack放业务相关属性)

ognl(object navigation language)

在struts2中ognl完成数据设置,类型转换两个功能

map上下文对象不常用数据存放地,userroot对象常用数据,不常用加#获取,如Ognl.getvalue("name",map,user); Ognl.getvalue("#name",map,user);

Ognl.getvalue("表达式",map,user);

struts2中通过ognl来设值和取值。ActionContest作为上下文对象,ValueStack作为ognl的root对象

在struts2中使用ognl表达式获取数据需要使用struts2的标签库,使用struts2的标签库需要注意页面一定是通过过滤器后才能解析struts2的标签

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>menu</title>
</head>
<body>
	登录成功,欢迎${username}<br/> <%--el表达式--%>
	<%--value填写ognl表达式--%>
	<s:property value="username" /><br>
	<s:property value="#application.address" /><br>
	<s:property value="#aparameters.username" /><br>
</body>
</html>

类型转换

在struts2中对于常用的数据类型已经自动进行了类型转换工作。但对于自定义类型struts2没法转换。需要自定义转换器来实现转换类型。
类型转换实现
新建类型转换器类继承StrutsTypeConverter类
还要建立配置文件

public class d extends StrutsTypeConverter {
    @Override
//    maps action context上下文
//    strings values,表单提交的字符串
//    aClass toclass
    public Object convertFromString(Map map, String[] strings, Class aClass) {
//        表单提交的数据在这个方法中被转换
//        返回值是目标对象,同时完成赋值
        return null;
    }

    @Override
    /*
    *将指定类型转换为String
    * 使用ognl表达式获取值时会调用该方法
    * */
    public String convertToString(Map map, Object o) {
        return null;
    }
}

文件

cn.sxt.vo.point=cn.sxt.converter.PointConverter
#point 对象 PointConverter 自定义转换器类

数据校验

数据校验分为2类,一类前段数据检验,一般js实现,一类是后端的数据校验。struts2提供了两种后端方法,一种编码实现,一种框架实现

硬编码

action需要继承ActionSupport类。在该类中提供了一个validate方法,只有方法执行通过后,才会执行业务方法
业务处理类
在validate方法中,添加了FieldError或ActionErrot那么方法不通过,并且返回结果为INPUT,所以需要配置INPUT处理结果集。在页面中添加struts2的标签库,并且添加错误标签。

Jsp页面:一定要加上<s:actionerror/>或者是<s:fielderror/>

<s:actionerror/>
   <form action="register.action" method="post">
   	用户名:<input type="text" name="name"/><br>
 	密码:<input type="password" name="pwd"/><br>
  	年龄:<input type="text" name="age"/><br>
   	生日:<input type="text" name="birthday"/><br>
 <input type="submit" value="登录"/>
   </form>
public class RegisterAction extends ActionSupport{
	private String name;
	private String pwd;
	private int age;
	private Date birthday;
	@Override
	public String execute() throws Exception {
		System.out.println("execute");
		return Action.SUCCESS;
	}
	public String register(){
		System.out.println("register");
		return Action.SUCCESS;
	}
	public void validateRegister(){
		System.out.println("validate age");
		if(age>100||age<1){
			this.addActionError("年龄不合法");
		}
	}
	public void validate() {
		System.out.println("validate");
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}

Struts.xml配置文件


<package name="default" extends="struts-default" namespace="/">
		<action name="register" class="cn.sxt.action.RegisterAction" method="register">
			<result>/index.jsp</result>
			<result name="input">/register.jsp</result>
		</action>
	</package>	

但是如果一个类中有多个业务方法,并且每个校验可能不一致,但所有的业务方法都会通过validate。导致功能不能实现。
如果需要为每个业务添加校验方法,验证方法名规则为validate+业务方法名(首字母大写)。这样执行顺序为validateXxx -->validate -->业务方法。这样validate填写的是公共校验

校验框架
在action所在包下,创建 + -validation.xml校验文件
创建注释可以在

<!--
  XWork Validators DTD.
  Used the following DOCTYPE.

  <!DOCTYPE validators PUBLIC
  		"-//Apache Struts//XWork Validator 1.0.3//EN"
  		"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
-->

里找

<validators>
	<!--field表示对哪一个表单域进行验证-->
	<field name="">
		<!--字段验证器,默认提供,根据-->
		<field-validator type="">
			<message>you must enter a name</message>
		</field-validator>
	</field>
</validators>

拦截器

struts2的所有功能都是由拦截器来实现。可以自定义拦截器来实现没有提供的功能。
struts2的默认拦截器都是定义在struts-default.xml中,所以在使用struts2时定义的package要直接或间接继承struts-default
使用内置拦截器时需要在action配置中引用

```csharp
<action name="getPwd class=“”
	<result name="success">/success.jsp</result>
	引用拦截器
	<interceptor-ref name=""></interceptor-ref>
</action>```

自定义拦截器
实现Interceptor接口或继承AbstractInterceptor类
定义。当引用自定义拦截器后,struts2的默认拦截器将不起作用,需要重新引用

实现Interceptor接口定义

package cn.cq.jszg.candidate;

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

public class MyInterceptor implements Interceptor {
    @Override
    public void destroy() {
//        销毁
    }

    @Override
    public void init() {
//        初始化
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
//        拦截器的主体实现
        /**
         * 当拦截器方法被调用后需要通过invocation.invoke调用下一个拦截器,如果没有拦截器那么执行action中的业务方法
         */
        System.out.println("自定义拦截器被执行了");
//        返回结果为结果集
        return invocation.invoke();
    }
}

在package标签中配置拦截器

	<package name="default" namespace="/" extends="struts-default">
<!--		拦截器的配置-->
		<interceptors>
<!--			name自定义,在项目中唯一-->
			<interceptor name="MyInterceptor" class="cn.cq.jszg.candidate.MyInterceptor"></interceptor>
			<interceptor-ref name="defautstrack"></interceptor-ref>
		</interceptors>
	</package>

在使用的action中引用拦截器

		<action name="save" class="" method="save">
<!--			使用自定义拦截器,有多个会从上往下执行-->
			<interceptor-ref name="MyInterceptor"></interceptor-ref>
		</action>

拦截器栈

拦截器栈就是一组拦截器,放在一个配置中,方便引用

<!--		定义拦截器栈,拦截器栈中可以引用另一个拦截器栈,可以引用多个拦截器,真正调用只需引用一个栈即可-->
		<interceptors>
			<interceptor-stack name="myStack">
				<interceptor-ref name="myInterceptor"/>
				<interceptor-ref name="defaultStack"/>
			</interceptor-stack>
		</interceptors>
		<action name="b" class="" method="">
			<interceptor-ref name="myStack"/>
		</action>

设置默认的拦截器栈

<!--设置默认拦截器栈-->
		<default-interceptor-ref name="myStack"></default-interceptor-ref>

struts2定义了默认的拦截器栈,defaultStack里面默认的18个拦截器

方法拦截器

拦截器拦截的是整个Action,action中所有业务方法都会被拦截。有时需要拦截某个方法。就用方法拦截器

实现

需要继承MethodFilterInterceptor

package cn.cq.jszg.candidate;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import ognl.MethodFailedException;

public class MethodInterceptor extends MethodFilterInterceptor {

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        System.out.println("方法拦截器执行");
        return invocation.invoke();
    }
}
<interceptor name="methodInterceptor" class="cn.cq.jszg.candidate.MethodInterceptor"/>
			<interceptor-ref name="methodInterceptor">
<!--				配置哪些方法配拦截,对应action中的hello,save方法-->
				<param name="includeMethods">hello,save</param>
<!--				配置哪些方法不被来接-->
				<param name="excludeMethods"></param>
			</interceptor-ref>

单文件上传

添加jsp页面,表单必须时post提交,并且设置enctype="multipart/form-data"
jsp

    <form action="xxx.action" method="post" enctype="multipart/form-data">
        文件:<input type="file" name="file" /><input type="submit" value="上传"/>
    </form>

处理类

package cn.cq.jszg.candidate;



import com.opensymphony.xwork2.Action;

import javax.swing.*;
import java.io.File;

/**
 * 文件上传类
 */
public class dateup {
//    file和表单域名称相同
    private File file;
    //上传文件的名称也是由struts2设置好
    //属性名=表单域名+FileName
    private String fileFileName;
    //文件类型 属性名=表单域名+Contenttype
    private String fileContenttype;

    //上传文件业务方法
    public String upload(){
        return Action.SUCCESS;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public String getFileFileName() {
        return fileFileName;
    }

    public void setFileFileName(String fileFileName) {
        this.fileFileName = fileFileName;
    }

    public String getFileContenttype() {
        return fileContenttype;
    }

    public void setFileContenttype(String fileContenttype) {
        this.fileContenttype = fileContenttype;
    }
}

配置

	<package name="default" namespace="/" extends="struts-default">
		<action name="dateup" class="cn.cq.jszg.candidate.dateup" method="upload">
			<result>/success.jsp</result>
			<!--设置上传单个文件大小-->
			<interceptor-ref name="fileUpload">
				<param name="maximumSize">xxx</param>
			</interceptor-ref>
		</action>
	</package>
	<!--设置文件上传临时目录-->
	<constant name="struts.multipart.saveDir" value="目录"></constant>
	<!--设置上传总文件大小,必须大于单个文件大小,bbb>xxx-->
	<constant name="struts.multipart.maxSize" value="bbb"></constant>

批量上传

页面

    <form action="xxx.action" method="post" enctype="multipart/form-data">
        文件1:<input type="file" name="file" /><br/>
        文件2:<input type="file" name="file" /><br/>
        文件3:<input type="file" name="file" /><br/><input type="submit" value="上传"/>
    </form>

事务类

package cn.cq.jszg.candidate;



import com.opensymphony.xwork2.Action;

import javax.swing.*;
import java.io.File;

/**
 * 文件上传类
 */
public class dateup {
//    file和表单域名称相同
    private File file[];
    //上传文件的名称也是由struts2设置好
    //属性名=表单域名+FileName
    private String fileFileName[];
    //文件类型 属性名=表单域名+Contenttype
    private String fileContenttype[];

    //上传文件业务方法
    public String upload(){
        return Action.SUCCESS;
    }

    public File[] getFile() {
        return file;
    }

    public void setFile(File[] file) {
        this.file = file;
    }

    public String[] getFileFileName() {
        return fileFileName;
    }

    public void setFileFileName(String[] fileFileName) {
        this.fileFileName = fileFileName;
    }

    public String[] getFileContenttype() {
        return fileContenttype;
    }

    public void setFileContenttype(String[] fileContenttype) {
        this.fileContenttype = fileContenttype;
    }
}

配置不变

文件下载

可以直接通过超链接下载,但不安全
通过流

package cn.cq.jszg.candidate;

import com.opensymphony.xwork2.Action;
import org.apache.struts2.ServletActionContext;

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

public class DownloadAction {
    private String filename;

    public String execuxe(){
        return Action.SUCCESS;
    }
    //结果集为stream需要返回InputStream类型
    public InputStream getInputStream() throws FileNotFoundException {
        String path = ServletActionContext.getServletContext().getRealPath(filename);
        return new FileInputStream(new File(path,filename));
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }
}

配置

	<package name="default" namespace="/" extends="struts-default">
		<action name="download" class="cn.cq.jszg.candidate.DownloadAction">
			<!--文件下载结果集类型为stream-->
			<result type="stream">
				<!--attachment下载框,filename设置下载时的文件名-->
				<param name="contentDisposition">attachment;filename=${filename}</param>
			</result>
		</action>
	</package>

处理异常

public class Myexception {
    private String name;
    private int a = 2;
    public String delet() throws Exception{
        System.out.println(a/0);
        return Action.SUCCESS;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
		<action name="delet" class="cn.cq.jszg.candidate.Myexception" method="delet">
			<result>/success.jsp</result>
			<!--发生异常
			exception为发生异常的类型,result和name一样
			-->
			<result name="exception">/excp.jsp</result>
			<exception-mapping exception="java.lang.Exception" result="exception"></exception-mapping>
		</action>

全局错误

<global-exception-mappings>
			<exception-mapping exception="java.lang.Exception" result="exception"></exception-mapping>
		</global-exception-mappings>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值