struts2学习笔记

 

 

1.系统开发流程分层

 

 

231751_rk94_2897732.png

2.struts2属于Mvc层

Struts2的下载地址http://struts.apache.org/download.cgi

目录结构:

234030_RL9j_2897732.png

3.struts2的例子

(1)解压struts2-blank.war包

(2)创建web项目;

(3)导入必要的jar包;

struts2-core-2.3.32.jar             Struts2的核心包

xwork-core-2.3.32.jar             WebWork的核心包

ognl-3.0.19.jar                      对象图导航语言(Object Graph Navigation Language)Struts2                                               通过其读写对象属性

freemarker-2.3.22.jar            Struts2的UI标签的模板使用freeMark编写

commons-logging-1.1.3.jar     日志包

commons-fileupload-1.3.2.jar    文件上传组件

commons-io-2.2.jar               传文件依赖的jar包

commons-lang3-3.2.jar          对java.lang包的增强

javassist-3.11.0.GA.jar            分析,编辑和创建Java字节码的类库

(4)编写jsp页面;

(5)编写action服务器端处理逻辑;

Action就是处理request请求的动作类,类似于servlet

(6)进行框架配置web.xml,struts.xml

struts.xml配置

1)在src文件下创建struts.xml文件,从APP例子中直接复制struts.xml的内容,然后删除<struts>标签里的内容,作为struts.xml的空文件

091236_MmS1_2897732.png
2)配置xml

<?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="hello" extends="struts-default">
<action name="hello" class="com.rl.action.HelloAction" method="hello">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>

web.xml配置

直接拷贝App例子中的web.xml文件,然后<web-app>标签里面只留<filter>和<filter-mapping>标签

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <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-app>

(7)测试;

 

4.struts的运行流程

141646_YX4g_2897732.png

1.启动服务(tomcat),加载web.xml,实例化StrutsPrepareAndExecuteFilter过滤器

2.在实例化StrutsPrepareAndExecuteFilter过滤器时会执行其中的init()方法,加载struts.xml文件

3.浏览器发起请求,会被StrutsPrepareAndExecuteFilter过滤器拦截到,根据请求的url(hello),找到相应的Action类,并且创建Action对象,执行相应的hello方法。

4.返回视图success.jsp  

 

5.struts2的配置文件

配置文件名称位置存储的内容说明
default.propertiesstruts2-core-2.3.32.jar/org/apache/struts2/default.properties通过属性的形式来配置struts2的参数不能直接修改
struts-default.xmlstruts2-core-2.3.32/struts-default.xmlstruts2的核心配置文件不能直接修改
struts-plugin.xml****-plugin.jar插件相关配置不能直接修改
struts.xml放在classpath应用配置文件开发人员使用,可以修改
struts.properties放在classpath应用配置文件(较少使用,不推荐)开发人员使用,可以修改

以上配置文件,服务器启动时会被加载,加载次序从上到下加载(启动服务-->过滤器StrutsPrepareAndExecuteFilter-->过滤器的init方法加载配置文件),按着配置文件的加载顺序,后加载的文件会把前面文件相同的配置的值覆盖

(1)default.properties

参数名称参数默认值说明
struts.i18n.encodingUTF-8框架使用的编码
struts.action.extensionaction,,请求的后缀名
struts.serve.static.browserCachetrue是否开启浏览器的静态缓存
struts.configuration.xml.reloadfalse每当struts.xml被修改时是否热部署
struts.devModefalse是否是开发者模式(包含上一属性)

通过<constant>标签配置来间接修改default.properties的属性,name和参数名称相同,value设置属性值

例如:172056_ME07_2897732.png

(2)struts-default.xml

该文件是struts的核心文件,里面提供了结果的返回类型和拦截器以及业务bean

结果的返回类型

174508_BPZO_2897732.png

拦截器

174617_jvAb_2897732.png

(3)struts.xml

开发人员编写的文件

包:package根据项目模块来划分的一个单元,一般在项目开发中,一个模块一个package

属性

name:包的名称,必须属性;

extends:包的继承,默认情况下我们必须继承struts-default,否则无法使用struts框架;

abstract:抽象包,不能包含action,其他的都可以有;

namespace:包的命名空间,值必须为“/***”格式,namespace用于请求访问某一个包的指定路径,目的区分不同的包的相同的action

动作:action每次请求所访问的方法

属性

name : 必须要有,访问方法是根据name来访问,http://localhost:8080/struts2_01/hello.action,后缀无需指定

class : 要访问的方法所在类

method : 方法名

结果:result要跳转的视图

属性

name:result的名称,是唯一的,返回哪一个视图是由action的返回值决定的,action返回值和result的name属性做匹配传,从而返回相应的视图

type : 跳转视图的方式,默认跳转方式是请求转发,地址栏没变

 

6.struts2的动作类(Action)

1)动作类的创建方式:

(1)使用普通方式JavaBean作为动作类,不需要继承任何父类,不需要实现任何接口

.方法一定是公用的(public)

.返回值是字符串来决定跳转到哪个视图

.不需要参数

.方法名自定义,如果不自定义,默认访问execute

 

(2)创建动作类,实现action接口

 接口:com.opensymphony.xwork2.Action

提供的一些常量

常量说明
SUCCESSsuccess返回成功页面
NONEnone不返回任何页面
ERRORerror返回错误页面
INPUTinput当提交表单发生错误时,就返回提交表单页面
LOGINlogin返回登录页面

(3)*创建动作类,继承父类(推荐使用)

父类:com.opensymphony.xwork2.ActionSupport

2)Action动作类的生命周期

创建:Action动作类每次请求的时候都会创建一个实例对象

销毁:当Action动作类的请求响应完后就消失了

跟JavaWeb中HttpServletRequest的生命周期是一样的,struts2是多例的,线程安全的

3)Action动作类的访问

通配符

原则:约定优于配置

在action中每个方法都要有一定的规则,eg.都以User结尾

223938_C6oo_2897732.png

225330_uHEQ_2897732.png

*是请求是输入的

225910_Pszi_2897732.png

注意:一个包里面只能有一个通配符Action

 

动态方法调用

首先打开动态方法的开关

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

我们的action动作类无需指定方法的method属性了,而是直接在url上指定

语法:!方法名[.后缀名]

eg.125007_AAH2_2897732.png

4).结果视图的配置

<result name="success">/success.jsp</result>

result : 要返回的视图

属性

name:action动作类要返回的值,如果的action动作类的返回值与result的name值匹配,则进行相应的跳转

type:跳转方式

type的常用值有:

dispatcher : 请求转发,地址栏不发生变化,相当于JavaWeb中的forward,当我们没有指定type的类型时,默认值是dispatcher

redirect:页面重定向,地址栏发生变化

chain:请求转发到一个action动作类,地址栏不发生变化(我测试的时候地址栏发生了变化,暂时不明白为什么)

redirectAction:重定向到一个action动作类,地址栏发生变化

同包的重定向:

132552_AEFE_2897732.png

不同包的重定向:result需要通过param来指定包的namespace和action的name

135029_k7Ra_2897732.png

stream:文件的上传和下载

5).局部结果视图和全局结果视图

在一个action中配置的result是局部结果视图,外部的action是不能使用这个result的

包级别的全局                                                                                                                                     (包内的全局结果视图对包内的每一个action动作类都有效)

<package name="hello3" extends="struts-default" namespace="/hello3">
	<!-- 包内全局结果视图 -->
	   <global-results>
	   <result name="error">/error.jsp</result>
	   </global-results>
		<action name="hello" class="com.rl.action.HelloAction" method="hello">
			<result name="success">hello2</result>
		</action>
		<action name="hello3" class="com.rl.action.HelloAction3" method="hello3">
			<result name="success">/success2.jsp</result>
		</action>
</package>

全局的结果视图                                                                                                                           (整个系统的全局结果视图通过继承的方式来实现

	<!-- 全局结果视图 -->
<package name="basePackage" extends="struts-default" abstract="true">
	<global-results>
	<result name="error">/error.jsp</result>
	</global-results>
</package>
<package name="hello3" extends="basePackage" namespace="/hello3">
	<action name="hello3" class="com.rl.action.HelloAction3" method="hello3">
	<result name="success">/success2.jsp</result>
	</action>
</package>

 

7.struts动作类获取ServletAPI

(1).使用ServletActionContext获得ServletAPI

        public String hello(){
        	/*获得page域对象,获取不到(很少使用)*/
        	PageContext pageContext=ServletActionContext.getPageContext();
        	/*获取request*/
        	HttpServletRequest request=ServletActionContext.getRequest();
        	/*获取response*/
        	HttpServletResponse response=ServletActionContext.getResponse();
        	/*获取session*/
        	HttpSession session=request.getSession();
        	/*获取application(请求)*/
        	ServletContext context=ServletActionContext.getServletContext();
        	System.out.println(pageContext);
        	System.out.println(request);
        	System.out.println(response);
        	System.out.println(session);
        	System.out.println(context);
        	return "success";
        }

(2).通过实现接口的方式来获取ServletAPI

接口:

org.apache.struts2.interceptor.ServletRequestAware;
org.apache.struts2.interceptor.ServletResponseAware;
org.apache.struts2.util.ServletContextAware;

public class HelloAction2 implements ServletRequestAware
,ServletResponseAware,ServletContextAware{
	   HttpServletRequest request;
	   HttpServletResponse response;
	   ServletContext context;
	
        public String hello(){
        	System.out.println(request);
        	System.out.println(response);
        	System.out.println(request.getSession());
        	System.out.println(context);
        	return "success";
        }

		@Override
		public void setServletRequest(HttpServletRequest request) {
			this.request=request;
		}

		@Override
		public void setServletResponse(HttpServletResponse response) {
			this.response=response;
		}


		@Override
		public void setServletContext(ServletContext context) {
			this.context=context;
		}
}

8.参数的封装

(1)静态封装

在运行器不发生变化的数据,或者一些配置相关的数据可以做静态封装

Action动作类                                                                                                                                     (用于接受静态的参数,必须提供set和get方法)

public class HelloAction {
	private String name = "zb";
	private String nn;

	public String hello() {
		System.out.println(name);
		System.out.println(nn);
		return "success";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getNn() {
		return nn;
	}

	public void setNn(String nn) {
		this.nn = nn;
	}
}

struts.xml配置                                                                                                                                   (<param>的name在action中必须有相应的属性,并且必须提供set和get方法,否则无法注入)

<package name="hello" extends="struts-default" namespace="/hello">
		<action name="hello" class="com.rl.action.HelloAction" method="hello">
		<param name="name">dzb</param>
		<param name="nn">NN</param>
		<result name="success">/success.jsp</result>
		</action>
</package>

(2)动态参数的封装

系统运行期间用户提交表单,Ajax请求,url访问。

1)动作类充当模型对象

动作类和模型合为一体,可以在动作类定义要接收的属性的值,对每个属性必须要提供set和get方法,动作类model属性一定要和表单中的name一致,否则无法注入。

jsp页面:

	<form
		action="${PageContext.request.contextPath}/struts2_09/hello/hello2">
		<table>
			<tr>
				<td>姓名</td>
				<td><input type="text" name="name" /></td>
			</tr>
			<tr>
				<td>年龄</td>
				<td><input type="text" name="age" /></td>
			</tr>
			<tr>
				<td>性别</td>
				<td><input type="radio" name="sex" value="nan"
					checked="checked" />男</td>
				<td><input type="radio" name="sex" value="nv" />女</td>
			</tr>
		</table>
		<button type="submit">提交</button>
	</form>

动作类model;

public class HelloAction2 {
	private String name;
	private int age;
	private String sex;

	public String hello() {
		System.out.println(name);
		System.out.println(age);
		System.out.println(sex);
		return "success";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

}

 

2)动作类和模型对象分离封装参数(推荐使用)

动作充当模型对象,动作类既是C层又是M层,可读性差,重用性差,很难维护,不推荐使用第一种方式。 这种方式接受参数对提交的表单中的name有要求,name值需要使用Action动作类的Model属性的名字加上点再加上要接收的属性名,如person.name;

jsp页面:

<form action="${pageContext.request.contextPath}/hello/hello3">
		<table>
			<tr>
				<td>姓名</td>
				<td><input type="text" name="person.name" /></td>
			</tr>
			<tr>
				<td>年龄</td>
				<td><input type="text" name="person.age" /></td>
			</tr>
			<tr>
				<td>性别</td>
				<td><input type="radio" name="person.sex" value="nan"
					checked="checked" />男</td>
				<td><input type="radio" name="person.sex" value="nv" />女</td>
			</tr>
		</table>
		<button type="submit">提交</button>
	</form>

model类:

public class Person {
	private String name;
	private int age;
	private String sex;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		System.out.println(name);
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
}

Action动作类:

public class HelloAction3 {
	private Person person;
	public String hello() {
		System.out.println(person);
		return "success";
	}
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
}

 

3)模型驱动方式封装参数(推荐使用)

第二种方式对页面上的文本域name的属性值有要求,必须要用model属性加上点再加上接受属性的名称,这样的话页面和Action动作类有侵入性(耦合性),模型驱动方式解决了这个问题,我们需要实现一个ModelDriven接口,使用接口中的getModel方法指定要接受的Model的类型,并且Action动作类中的model对象必须手动创建,否则无法注入属性

jsp页面:

<form action="${pageContext.request.contextPath}/hello/hello4">
		<table>
			<tr>
				<td>姓名</td>
				<td><input type="text" name="name" /></td>
			</tr>
			<tr>
				<td>年龄</td>
				<td><input type="text" name="age" /></td>
			</tr>
			<tr>
				<td>性别</td>
				<td><input type="radio" name="sex" value="nan"
					checked="checked" />男</td>
				<td><input type="radio" name="sex" value="nv" />女</td>
			</tr>
		</table>
		<button type="submit">提交</button>
	</form>

Model类跟上一种方式的一样:

public class Person {
	private String name;
	private int age;
	private String sex;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		System.out.println(name);
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
}

Action动作类:

public class HelloAction4 implements ModelDriven<Person> {
	private Person person = new Person();

	public String hello() {
		System.out.println(person);
		return "success";
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}

	@Override
	public Person getModel() {
		// TODO Auto-generated method stub
		return person;
	}
}

 

9.类型转换

(1)类型转换认识

页面所提交过来的数据都是字符串类型的数据,而model里面的数据并不都是字符串数据,有各种各样的类型,我们使用servlet接收数据时都是自己手动转换的,而struts2可以为我们自动转换,转换的前提是前端页面提交过来的字符串数据可以和model中相应的数据类型可以转换。

提交表单时:字符串类型 ----> 其他数据类型

展示页面时:其他数据类型 ---> 字符串类型

表单提交数据时,数据的转换虽然struts2做了大多数,但是时间类型往往需要我们根据实际情况手动做相应的转换。

(2)自定义类型转换

             220958_2snu_2897732.png

日期转换:

默认情况下,struts2解析的时间的格式是“yyyy-MM-dd”

第一步:通过自定义类型转换器继承StrutsTypeConverter做日期转换器

public class DateConverter extends StrutsTypeConverter {

	@Override
	public Object convertFromString(Map context, String[] values, Class toClass) {
		Date date = null;
		if (values != null && values.length > 0) {
			if (toClass == Date.class) {
				try {
					date = new SimpleDateFormat("yyyy/MM/dd").parse(values[0]);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					throw new RuntimeException();
				}
			}
		}
		return date;
	}

	@Override
	public String convertToString(Map context, Object o) {
		String dateStr = null;
		if (o != null && o.getClass() == Date.class) {
			dateStr = new SimpleDateFormat("yyyy/MM/dd").format((Date) o);
		}
		return dateStr;
	}

}

第二步:注册日期类型转换器

局部注册:

  在要转换的model类的同级包下创建一个属性文件,                                                                           命名要求:model类名-conversion.properties                                                                                 在文件的内部,key是要转换的属性名,value是转换器的全路径

164710_RLtd_2897732.png

 

全局注册:

如果有很多的Model类都有时间类型,那么使用局部注册就需要创建很多注册文件,这样不合理,这种情况就需要全局注册

170245_y1nv_2897732.png

(3)获取页面的错误提示信息:

在jsp页面添加

<%@ taglib uri="/struts-tags" prefix="s"%>

然后用

<s:fielderror></s:fielderror>

输出错误

230447_fU0U_2897732.png

230843_baXv_2897732.png

230218_An9B_2897732.png

230941_GIbM_2897732.png

把错误信息转换成中文:

第一步:在Action的同级包下创建一个属性文件,规则:和Action类同名.properties

第二步:Key : invalid.fieldvalue.[要转换的表单中文本域的name],value是中文的提示信息,中文在properties文件中以Unicode编码的形式存在

           232233_FCdL_2897732.png

 

10.struts2数据校验

验证的方式有两种

客服端校验:使用js结合正则表达式来校验,不和服务器打交道,开发简单,安全性差,

服务端校验:请求服务器,开发量比较大,安全性好,需要和数据库交互必须使用服务端校验。

实际开发中,客服端校验较多,最好是客服端和服务端都校验。

strusts2的校验属于服务器端校验。

1.struts2编程式校验

编程式校验,重写父类(ActionSupport)的validate方法,在这个方法中,对每一个字段做校验,如果参数不符合正则表达式,我们可以添加提示信息,由addFieldError方法来向页面输出提示信息。但是校验的前提是提交过来的参数是能互相转换的,如果转换不了的话会由param,modelDriven拦截器来负责。

	/**
	 * validate在封装参数之前做验证,如果不通过就跳转到表单页面
	 */
	@Override
	public void validate() {
		if (!person.getName().matches("[a-zA-Z]{3,8}")) {
		/*	添加提示信息,第一个参数是表单中文本域的name,第二个参数是提示信息*/
		  addFieldError("name","姓名只能是3到8位大小写字母!");	
		}
		if (!(person.getAge()+"").matches("\\d{1,3}")) {
			/*	添加提示信息,第一个参数是表单中文本域的name,第二个参数是提示信息*/
			  addFieldError("age","年龄只能是1到3位数字!");	
		}
	}

2.struts2声明式校验

转载于:https://my.oschina.net/ThreeTiger/blog/1457255

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值