文档章节

Struts2的其它知识

pmos
 pmos
发布于 2016/11/02 22:36
字数 3005
阅读 16
收藏 2

4、Struts2的其它知识

    4.1、ModelDriven

    如果希望传递对象信息到action,但对象信息较多时,需要传递大量的参数并且要设置这些参数,工作量
    很大,所以建议的方式是在action中直接创建相应的对象,此时在jsp页面中可以通过如下一种方式进行参
    数的传递:

	<form action="Message_add.action" method="post">
	<!-- 在传递值的name中,加上action的对象msg的名称 -->
		ID:<input type="text" name="msg.id"/><br/>
		Title:<input type="text" name="msg.title"/><br/>
		Content:<input type="text" name="msg.content"/><br/>
		<input type="submit"/>
	</form>

    但是使用这样的方式带来的问题是在表单中的名称不能按照我们开发人员的习惯来定义,此时就需要通过
    ModelDriven来实现如下传值:

    1、让action实现ModelDriven接口。

    2、覆盖getModel()方法

	@Override
	public Message getModel() {
		if(msg==null) msg = new Message();
		return msg;
	}

    3、当一个类实现了ModelDriven之后,就会将这个model放入到root中,所以我们的input中不用加任何的
    对象信息就可以直接放置到msg对象中。

    特别注意:使用ModelDriven存在的问题:更新时获取的是root中的新对象,所有的值都为空。

    可以通过如下方式解决:

public class MessageDao {
	public Message load() {
		Message msg = new Message();
		msg.setId(12);
		msg.setTitle("办证");
		msg.setContent("专业办证二十年");
		return msg;
	}
	public String updateInput() {
		try {
           //展示页面需要通过value='<s:property value="msg.id"/>'来获取值,如果希望直接通过id来获取值,
           //可以通过以下两种方式来实现
			MessageDao md = new MessageDao();
			Message tmsg = md.load();
            //第一种方式:将root中的对象通过取到的值重新赋值
			/*msg.setId(tmsg.getId());
			msg.setTitle(tmsg.getTitle());
			msg.setContent(tmsg.getContent());*/
            //第二种方式:通过BeanUtil实现赋值
			BeanUtils.copyProperties(msg, tmsg);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return "success";
	}
	<s:debug/>
	<form action="Message_add.action" method="post">
	<!-- action中重新赋值后就可直接通过id来获取值(value='<s:property value="id"/>') -->
		ID:<input type="text" name="id" value='<s:property value="id"/>'/><br/>
		<!-- 如果没有在action中赋值,则需通过action中的对象msg来获取值(msg.title) -->
		Title:<input type="text" name="title" value='<s:property value="msg.title"/>'/><br/>
		Content:<input type="text" name="content" value='<s:property value="msg.content"/>'/><br/>
		<input type="submit"/>
	</form>

    4.2、类型转换

    当使用ModelDriven来实现参数接收时,可能由于类型的不一致(特别是一些复杂类型)导致接收参数报
    错,此时就需要使用类型转换器。

    类型转换器有两种模式:一种全局模式(所有的action均有作用),另外一种是局部模式(针对某个特定
    的action起作用)。

    全局模式实现步骤:

    1、写一个类继承StrutsTypeConverter

/**
 * 要为某个对象增加相应的类型转换器,首先得创建一个类继承StrutsTypeConverter
 * @author PM
 *
 */
public class PointConverter extends StrutsTypeConverter {
	/**
	 * 完成字符串到对象的转换
	 */
	@Override
	public Object convertFromString(Map context, String[] values, Class toClass) {
		Point p = null;
		if(values.length<=1) {
			String str = values[0];
			//12,88
			p = new Point();
			String[] cods = str.split(",");
			p.setX(Integer.parseInt(cods[0]));
			p.setY(Integer.parseInt(cods[1]));
		}
		return p;
	}
	
	/**
	 * 完成对象到字符串的转换
	 */
	@Override
	public String convertToString(Map context, Object o) {
		Point p = (Point)o;
		return p.getX()+","+p.getY();
	}

    2、在类路径创建xwork-conversion.properties文件,在这个文件中说明要转换的对象

org.struts.model.Point = org.struts.converter.PointConverter

    org.struts.model.Point:表示要转换的对象

    org.struts.converter.PointConverter:表示使用哪一个转换器来转换。

    以上的全局转换器是针对所有的需要转换的类来指定,但是有时候可能会根据不同的action来进行转换,
    这个时候就会使用到局部转换器。

    1、创建一个类继承StrutsTypeConverter

public class DateConverter01 extends StrutsTypeConverter {
	//定义了日期的格式
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	
	@Override
	public Object convertFromString(Map context, String[] values, Class toClass) {
		try {
			if(values.length<=1) {
				String d = values[0];
				return sdf.parse(d);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public String convertToString(Map context, Object o) {
		return sdf.format((Date)o);
	}
public class DateConverter02 extends StrutsTypeConverter {
	//定义了日期的格式
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
	
	@Override
	public Object convertFromString(Map context, String[] values, Class toClass) {
		try {
			if(values.length<=1) {
				String d = values[0];
				return sdf.parse(d);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public String convertToString(Map context, Object o) {
		return sdf.format((Date)o);
	}

    2、在action所在的包中创建ActionName-conversion.properties(如:MessageAction-
            conversion.properties)

msg.createDate = org.struts.converter.DateConverter01
endDate = org.struts.converter.DateConverter02

    msg.createDate、endDate:表示action中的要转换的对象的名称,此处等于要转换该action中的msg的
    createDate和action中的endDate两个属性。

    在action所在的包中创建ActionName-conversion.properties来设置转换器。

    4.3、文件上传

    Struts2对文件上传提供了天生的支持,只要设置一个表单域为file并且将form的类型提供为
    multipart/form-data,Struts2会自动完成普通表单和文件表单的识别。

    1、定义一个文件提供相应的上传form

	<s:debug/>
	<form action="Message_file.action" method="post" enctype="multipart/form-data">
		<!-- 有一组file只要在Action中设定一个数组来接收,
			如果只有一个file,就设定一个对象来接收 -->
		Title:<input type="text" name="title"/><br/>
		File:<input type="file" name="photo"/><br/>
		File:<input type="file" name="photo"/><br/>
		File:<input type="file" name="photo"/><br/>
		File:<input type="file" name="photo"/><br/>
		File:<input type="file" name="photo"/><br/>
		<input type="submit"/>
	</form>

    2、在Action中定义相应的属性来接收file对象,如果是一组属性定义一个数组,如果是一个属性定义一个
    对象。属性的名称必须是表单中的name名称。

	//photo名称必须和表单中的名称一样,但是这个file中没有相应的文件名
	private File[] photo;
	//文件名需要通过定义其它的参数来接收,关键是需要两个set方法,
	//一个用来设置文件名称
	private String[] photoFileName;
	//一个用来设置文件类型
	private String[] photoContentType;
	
	/**
	 * 会把上传的文件名通过该方法获取
	 * @return
	 */
	public String[] getPhotoFileName() {
		return photoFileName;
	}
	
	/**
	 * 上传的文件名会通过该方法设置
	 * 用来接收文件名的方法,如果表单的名称是photo,这个名称必须是setPhotoFileName()
	 * @param photoFileName
	 */
	public void setPhotoFileName(String[] photoFileName) {
		this.photoFileName = photoFileName;
	}

	public String[] getPhotoContentType() {
		return photoContentType;
	}
	/**
	 * 设置文件类型,不论是文件名还是文件类型,所使用的格式是固定的
	 * xxxFileName,xxxContentType
	 * 用来接收上传文件的类型的,如果名称是photo,这个函数的名称必须是setPhotoContentType()
	 * @param photoContentType
	 */
	public void setPhotoContentType(String[] photoContentType) {
		this.photoContentType = photoContentType;
	}

	public File[] getPhoto() {
		return photo;
	}

	public void setPhoto(File[] photo) {
		this.photo = photo;
	}

    特别注意:Struts2默认上传文件的大小是有限制的(default.properties),可以通过struts.xml来配置修改

	<!-- 设置上传文件的大小(字节数) -->
	<constant name="struts.multipart.maxSize" value="10240000"/>

4.4、拦截器

    拦截器是Struts2中非常重要的一种控制手段,在开发中可以使用拦截器来拦截用户的请求,并且进行相应
    的权限控制。

    1、创建拦截器:写一个类继承AbstractInterceptor

public class HelloInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("heelo interceptor");
		//拦截请求完成之后,需要继续向下走,调用invocation.invoke()
		return invocation.invoke();
	}

    2、配置拦截器

    2.1、先创建拦截器

    <package name="default" namespace="/" extends="struts-default">
    	<interceptors>
    	<!-- 创建了一个拦截器的配置,但是此时配置并没有生效,需要在action中配置之后才能生效 -->
    		<interceptor name="helloInterceptor" class="org.struts.interceptor.HelloInterceptor"/>
    	</interceptors>

    2.2、在action中使用拦截器

		<action name="*_*" class="org.struts.action.{1}Action" method="{2}">
			<!-- 在action中引入相应的拦截器 -->
			<interceptor-ref name="helloInterceptor"/>

问题:当时用了这个拦截器之后,出现了一个问题,原来应该传的值都变为null了?

是因为当我们设定了拦截器之后,默认拦截器就不起作用了(默认拦截器是在struts-default.xml中设定
的),所以在创建新的拦截器时必须可以拥有原有的默认拦截器,可以使用拦截器栈来处理。

    <package name="default" namespace="/" extends="struts-default">
    	<interceptors>
    	<!-- 创建了一个拦截器的配置,但是此时配置并没有生效,需要在action中配置之后才能生效 -->
    		<interceptor name="helloInterceptor" class="org.struts.interceptor.HelloInterceptor"/>
    		<!-- 定义了一个拦截器栈,包含有默认的拦截器和自己定义的拦截器 -->
    		<interceptor-stack name="helloStack">
    			<interceptor-ref name="defaultStack"/>
    			<interceptor-ref name="helloInterceptor"/>
    		</interceptor-stack>
    	</interceptors>
		<action name="*_*" class="org.struts.action.{1}Action" method="{2}">
			<!-- 引用时就引用自己的拦截器栈 -->
			<interceptor-ref name="helloStack"/>

4.5、国际化(I18N)

    1、国际化的概念:

        ResourceBundle可以支持国际化,通过配置文件(.properties)完成国际化的支持的。

    2、创建配置文件的要求:

        Message_zh_CN.properties(Message表示基础名称,zh表示中文,_CN表示的是国家的编码,可以
        省略)。

        Message_en_UK.properties(针对美国英语的配置文件,同样也可以省略_UK)。

    3、使用java.util中ResourceBundle可以实现

public class TestI18n {
	public static void main(String[] args) {
		//创建ResourceBundle对象,并且说明区域名称(CHINESE或者ENGLISH等)
		ResourceBundle rb = ResourceBundle.getBundle("Message", Locale.CHINESE);
		//根据key来获取值,此时就会根据ResourceBundle创建时的区域名称来相应的properties文件中取数据
		System.out.println(rb.getObject("hello")+","+rb.getObject("world"));
	}

    4、Struts2的实现:局部的、全局的

    局部的一般不使用。

    全局的有两种方式:

    4.1、针对package的全局设定

        在Action的所在包的任何路径下创建package_zh.properties和package_en.properties。

    在这两个文件中加入相应的key和value。

message.id=标识
message.title=标题
message.content=内容
message.id=ID
message.title=Title
message.content=Content

    让需要进行国际化的Action实现ActionSupport类之后在页面中使用<s:text name=""/>完成调用。

		<s:text name="message.id"/>:<input type="text" name="id"/><br/>
		<s:text name="message.title"/>:<input type="text" name="title"/><br/>
		<s:text name="message.content"/>:<input type="text" name="content"/><br/>
		<input type="submit"/>

    4.2、全局国际化

        在类路径下创建相应的资源文件。

    在struts.xml配置中加入全局资源文件的名称.

	<!-- 设置国际化,value="Message"指定国际化文件的baseName(基本名称) -->
	<constant name="struts.custom.i18n.resources" value="Message"/>

4.6、Struts2的常用标签

    Struts2提供了一组非常好用的Form来帮助我们完成开发。

    1、Struts2的theme:Struts2提供一组主题帮助开发者来实现界面操作。默认主题是xhtml。

    修改主题可以在struts.xml配置文件中设置。

	<!-- 设置显示主题样式 -->
	<!-- <constant name="struts.ui.theme" value="simple"/> -->

    2、常用标签

public class GroupAction implements ModelDriven<Group> {
	private Group group;
	
	public Group getGroup() {
		return group;
	}

	public void setGroup(Group group) {
		this.group = group;
	}

	public String addInput() {
		group.setId(1);
		group.setName("财务部");
		List<String> interest = new ArrayList<String>();
//		interest.add("football");
		interest.add("pingpong");
		List<Group> groups = new ArrayList<Group>();
		groups.add(new Group(1,"财务部"));
		groups.add(new Group(2,"文章审核人员"));
		groups.add(new Group(3,"超级管理员"));
		groups.add(new Group(4,"文章发布人员"));
		ActionContext.getContext().put("username", "张三");
		ActionContext.getContext().put("groups", groups);
		ActionContext.getContext().put("interest", interest);
		return "success";
	}

	@Override
	public Group getModel() {
		if(group==null) group = new Group();
		return group;
	}
	<s:debug/>
	<s:form action="Group_add" method="post">
		<!-- s:textfield会显示文本输入框,并且会自动将root中的值根据name设置进来 -->
		<s:textfield label="组标识" name="id"/>
		<s:textfield label="组名称" name="name"/>
		<!-- 在Struts2中要在Struts2的标签中引入相应的ActionContext中的值,要使用%{xxx} -->
		<s:textfield label="用户名" name="username1" value="%{username}"/>
		<!-- 对于列表而言,在新版本中已经可以使用#xxx来访问,但是依然建议使用%{}来访问 -->
		<s:checkboxlist label="兴趣" name="interest" 
		list="#{'football':'足球','basketball':'篮球','pingpong':'乒乓球' }" 
		listKey="key" listValue="value" value="%{interest}"/>
		<!-- 创建了一组单选框 -->
		<s:radio list="#{'0':'男','1':'女' }" value="0" name="gender" label="性别"/>
		<!-- 创建了一个下拉列表框 -->
		<s:select list="#groups" listKey="id" listValue="name" label="选择组" 
		headerKey="-1" headerValue="请选择相应的组" value="2"/>
		<s:submit value="添加"/>
	</s:form>

   4.7、Struts2提供了大量的服务器端验证方法(XML、Annotation等)。

	/**
	 * 在执行某个方法之前如果有validateXX,都会先执行这个方法
	 */
	public void validateAdd() {
		if(msg.getId()<0) {
			this.addFieldError("id", "标识必须大于0");
		}
		if(msg.getTitle()==null||"".equals(msg.getTitle())) {
			this.addFieldError("title", "标题不能为空");
		}
	}
	<!-- 错误信息在一处显示 -->
	<s:fielderror/>
	<!-- 显示错误信息必须使用Struts的标签 -->
	<s:form action="Message_add" method="post">
		<s:textfield key="message.id" name="id"/>
		<s:textfield key="message.title" name="title"/>
		<s:textfield key="message.content" name="content"/>
		<s:submit/>
	</s:form>
	<!-- 只在一处显示id的错误信息 -->
	<s:fielderror fieldName="id"/>

4.8、Struts2异常处理

    	<global-results>
    		<result name="error">/WEB-INF/inc/error.jsp</result>
            <!-- 异常信息页面 -->
    		<result name="exception">/WEB-INF/inc/exception.jsp</result>
    		<result name="loginInput">/WEB-INF/Login/input.jsp</result>
    	</global-results>
    	<!-- 定义异常处理 -->
    	<global-exception-mappings>
    		<exception-mapping result="exception" exception="org.struts.exception.MyException"/>
    	</global-exception-mappings>
	<h1 style="color: #f00">发生错误</h1>
	<!-- 获取异常信息 -->
	${exception.getMessage() }

 

© 著作权归作者所有

共有 人打赏支持
上一篇: log4j基本操作
下一篇: Struts2 OGNL
pmos
粉丝 12
博文 127
码字总数 212660
作品 0
其它
项目经理
私信 提问
请大家指点,学STRUTS2……

熬了几夜,感觉对struts2中的action认识提高了不少,想请大家指点一二,请不吝赐教。 第一、我用DAO这种模式搞,思路是:用JSP作提交和结果显示界面,用action处理JSP请求,并在action中校验...

temp1898
2011/03/29
559
11
Struts2中OGNL,valueStack,stackContext的学习

[/color]学习Struts2,一直不明白表单中的值是怎么传给Action的,上网查了些资料,基本了解了!下面基本是从几个人的BOLG转载过来,以后记不清了再来看~ [color=red]先看看我做的实验jsp页面...

杨松坤
2012/07/19
0
0
请教一个关于struts的问题

在网上看关于struts2的知识,都说struts2集合了webwork和struts1的优点,但是我就是没发现struts2哪里吸收了strut1的优点? 求解释?

sonxuegeng
2011/08/26
468
4
请问struts2吸收了struts1的什么优点?

在网上看关于struts2的知识,都说struts2集合了webwork和struts1的优点,但是我就是没发现struts2哪里吸收了strut1的优点? 求解释?

sonxuegeng
2011/08/25
608
5
千里马加班不要加班费出差不要出差费

会JSP、Servlet、JDBC、JavaBean等web编程技术; 会Hibernate、Struts2、Spring三大框架及一些常用小框架; 会使用MyEclipse集成开发环境进行Java软件开发及其它相关工具软件操作; 会HTML、...

Andy男人
2012/07/13
1K
31

没有更多内容

加载失败,请刷新页面

加载更多

指针数组和数组指针的区别

这两个名字不同当然所代表的意思也就不同。我刚开始看到这就吓到了,主要是中文太博大精深了,整这样的简称太专业了,把人都绕晕了。从英文解释或中文全称看就比较容易理解。 指针数组:arr...

天王盖地虎626
32分钟前
1
0
Qt那些事0.0.18

今天要记一下Qt中的Resource。自我感觉理解的不错,但是还会难免有谬误,在日后有可能会更新,也有可能不会。 小声的念叨一句,女人心,海底针。 今天就直接跳过了关于QML在qrc文件中的介绍,...

Ev4n
40分钟前
1
0
深入解析js的作用域、预解析机制

虽然,ES6在我们工作中应用得越来越广泛,但是还是很多项目保留着ES5的写法,所以,今天,带着大家重新巩固下ES5下的作用域及预解析机制。 概念: 作用域:域,指的是一个空间、范围、区域,...

前端攻城老湿
43分钟前
1
0
Spring Cloud Feign - 声明式 REST Client

1、Feign是什么 声明式REST client,来自NetFlix。 允许你编写无实现代码调用REST services 替换RestTemplate(甚至更简单) Spring Cloud 为使用Feign提供了包装器 2、怎样使用Feign 对比:...

Benz001
48分钟前
3
0
前端、后端和全栈到底不该学什么

1、前言 在职业规划咨询过程中经常会被问到这样的问题: 老师,我是该深入钻研专精一门,走技术大牛路线,还是所有都要精通,做一个全栈工程师? 类似问题的变种还有,老师我是不是该30岁最迟...

前端攻城小牛
50分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部