在之前我有写过关于struts2框架的博客,好像是写了三篇,但是之前写的内容仅仅是struts2的一些基础知识而已,struts2还有很多有趣的内容等待着我们去发掘。我准备再写几篇关于struts2的高级内容,之前的一些基础知识我就不会再提了,所以,在看进阶篇的struts2时,我希望你有一定的struts2框架的基础,没有的话也不要紧,因为入门struts2非常简单,随手看几篇博客就算入门了,但要想灵活运用它,我们就得付出大量的时间和精力,让我们为了共同的目标奋进吧。

那就先补充一些知识点,这些知识点在之前是没有提到过得。

<package name="demo" extends="struts-default" namespace="/">
<action name="hello" class="com.itcast.demo.HelloAction" method="">
<result name="ok">/index.jsp</result>
</action>
</package>

这是struts.xml配置文件的一段配置,这段配置相信大家都能懂吧,不懂的话你就应该去补补课了。还是来解释一下吧,package元素可以把逻辑上相关的一组Action、Result、Intercepter等元素封装起来,形成一个独立的模块,package可以继承其他的package,也可以作为父包被其他的package继承,在上面的配置中,我们package标签配置了name属性为demo,这是模块的名称,名称是唯一的,然后是extends属性,这个属性如何理解,我们可以这样想,一个类继承了HttpServlet,它就成为了Servlet,那么我们的package也要继承struts-default,它才能起作用,然后是命名空间namespace。该属性值和action标签的name属性值共同构成访问路径。也就是说,我们在浏览器输入 /hello,即可访问到action标签配置的action类,如果namespace属性值为/demo,则访问路径变为 /demo/hello。

说到action,我们就来了解一下关于action的内容。在action标签中,需要配置class属性值,该属性值即是action类路径,这个类是用来处理逻辑的,也就是说,用户在访问一个网页地址时,会通过地址寻找对应的package,然后在package内寻找具体的action标签,当匹配到某个action时,struts框架就会寻找class属性值所对应的类,在action标签里还有一个method属性,它指定运行的方法,如果不配置method,默认执行execute()方法。还需要注意的是,如果在action标签中你没有配置result,程序是会报错的,除非你的方法返回值为none,你才可以不用配置result标签。

我们知道,action类需要继承ActionSupport,其实,要想实现action,我们有三种方式。

查看源码,我们知道ActionSupport实际上实现了一个Action接口,所以,我们也可以通过实现action接口来实现action类。

还有一种方式就是什么类也不继承,什么接口也不实现,这样的类也是可以成为action类的。

<!--
当action类的方法非常多时,相应的action配置也会很多,这时,我们可以通过通配符*进行统一配置
当action的name属性写为hello3_*的时候,我们访问所有关于hello3_的路径都会被action捕获,例如:hello3_update、hello3_add
而此时方法名也应该随着我们访问的路径进行改变,所以这里使用占位符进行配置,{1}则表示第一个通配符的内容 在struts2.5之后的版本,会有一个权限的问题,所以method属性值光写一个{1}还不行,还需要配置一个allowed-methods标签,且必须配置在result标签之后
-->
<action name="hello3_*" class="com.itcast.demo.HelloAction" method="{1}">
<result name="update">/index.jsp</result>
<result name="add">/index.jsp</result>
<result name="ok">/index.jsp</result>
<allowed-methods>add,update</allowed-methods>
</action>

这是关于action配置的问题,不作过多赘述,注释已经写得很清楚了。

既然我们已经能够通过struts框架来控制网页了,我们就可以将以前用servlet写的项目替换为用struts框架来写,但是会发现一个问题,之前我们使用的Servlet的API在action类中根本就没有,其实,struts框架已经为我们准备好了,我们有三种做法。

第一种,通过实现感知接口来得到域对象,如:request、response、session、cookie等。其中ServletRequestAware用来获得request对象,ServletResponseAware用来获取response对象,SessionAware接口用来获取session对象。通常我们会创建一个BaseAction类来实现这些接口,获取域对象,然后接下来的action类都去继承BaseAction类从而间接获得域对象。

第二种,通过ServletActionContext工具类去获取域对象,该工具类提供了一系列方法用于获取域对象,细节不作讲述。

第三种,通过ActionContext获得,其实前两种方法已经能够很轻松地获得域对象了,那么为什么还会出现第三种方法呢,这是因为前两种方法的耦合严重,而第三种方法则不会牵扯到Servlet的相关内容。那么如何获取域对象呢?通过ActionContext的getContext()方法得到一个上下文,这是整个Action的上下文,再通过上下文的getSession()方法获得session对象。注意,request和response对象并不是像获取session这样得到的,它提供了一个getParameters()方法,该方法返回HttpParameters对象,这就是request对象,它通过一个键名获得一个对象,该对象就是我们传递的参数信息了。

通过查阅getSession()的源码我们知道,getSession()方法调用就是类内容的get()方法。

/**
* Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
*
* @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
*/
public Map<String, Object> getSession() {
return (Map<String, Object>) get(SESSION);
}

那get()方法是什么呢?

/**
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
*
* @param key the key used to find the value.
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
*/
public Object get(String key) {
return context.get(key);
}

所以我们可以不使用getSession()方法来获取session对象,可以通过context.get(ActionContext.SESSION)。同理,其它的一些对象我们也可以通过这样的方式来获取。而常量的定义里并没有request,所以,我们无法拿到request对象,如果您非要用这样的方法来获取request,你也可以这样写,context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest")。我们可以在源码中找到这样一个常量。

/**
* Constant for the HTTP request object.
*/
public static final String HTTP_REQUEST = "com.opensymphony.xwork2.dispatcher.HttpServletRequest";

所以这样获取request对象也是可以的。

接下来说一说Action参数的三种接收方式。

其实参数可以通过requestAPI进行获取,那为什么还要单独介绍Action接收参数呢?注意了,这和requestAPI获取参数可不一样。怎么做呢,很简单,我们在Action类中定义一个变量sname,然后提供它的setXXX方法,接着我们定义了一个方法,用于输出变量的值。

public String demo(){
System.out.println("sname = " + sname);
return NONE;
}

然后在struts.xml文件中配置。

<action name="hello4" class="com.itcast.demo.HelloAction" method="demo"/>

我们运行项目,在浏览器上输入http://localhost:8080/struts_demo1/hello4?sname=zhangsan ,然后回车,会发现控制台打印出了信息。



是不是很神奇呢?其实它底层使用的是反射技术来获取你的类成员变量,然后对其调用setXXX方法进行赋值,你才能够很简单地取到请求参数。所以,这样获取参数的好处在哪呢?我们知道,request对象的getParamater()方法取到的参数值永远是String类型,但是,用Action类成员变量来获取值就没有这样的问题了,因为底层已经帮我们实现了封装,我们可以尝试一下。

再加入一个Integer类型的变量sid,然后提供setXXX方法,修改一下我们的demo方法。

public String demo(){
sid += 1;
System.out.println("sname = " + sname + ",sid = " + sid);
return NONE;
}

接着我们运行项目,在浏览器上输入http://localhost:8080/struts_demo1/hello4?sname=zhangsan&sid=111 ,控制台输出信息如下。



sid的值变为2,这就可以说明它是Integer类型,是可以进行数学运算的。而当你将字符串作为sid的参数值进行传递的时候程序就会报错。

以上介绍的是第一种获取参数的方法,这种方法有什么缺陷呢?当属性非常多的时候,对应的setXXX方法也会非常多,这是很不好的,那么接下来我介绍第二种方法。

第二种方法就是将这些成员变量提取成为一个JavaBean。

package com.itcast.demo;

public class User {

	private String sname;
private Integer sid;
private Integer age; public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public String getSname() {
return sname;
} public Integer getSid() {
return sid;
} public void setSid(Integer sid) {
this.sid = sid;
} public void setSname(String sname) {
this.sname = sname;
} @Override
public String toString() {
return "User [sname=" + sname + ", sid=" + sid + ", age=" + age + "]";
}
}

然后我们将User对象作为成员变量,提供setXXX方法,现在我们来探讨一个问题。

private User user;
private User user2; public void setUser(User user) {
this.user = user;
} public void setUser2(User user2) {
this.user2 = user2;
}

假设我们有两个User对象,user和user2,那么我们在进行参数传递的时候,它是怎么进行赋值的呢?是赋值给user还是user2呢?当然,程序不会这么智能,这是需要我们去控制的,如果你想将参数传递给user,你就可以将地址这样写:http://localhost:8080/struts_demo1/hello4?user.sname=zhangsan&user.sid=1&user.age=18 ,如果想将参数传递给user2,就将参数前面的对象名改为user2即可,然后我们运行程序,访问该网址,控制台输出如下。



会发现,我们只取到了sname的值,其它两个值并没有取到,这是因为String和Integer变量值的存储位置不同导致,这里不作过多讲解,我们只需要提供user对象的getXXX方法即可获得另外两个参数值。

接下来介绍第三种方法,虽然不太常用,但也需要了解一下。

我们将Action类实现ModelDriven接口,该接口需要一个泛型,我们将User类作为泛型传入,然后实现接口的方法,从这里我们就可以看到这种方法的局限性,它只能用来处理一种Bean类的情况,所以绝大多数情况下我们都不会去使用第三种方法。

我们继续研究Action获取参数,下面我们来看看Action是如何获取数组集合等类型参数的。

我们新建一个Action类ParamAction,然后配置一下。

<action name="param" class="com.itcast.demo.ParamAction" />

那么我们分三种情况来说,分别是数组、集合和Map。

首先是数组,Action如何获取到数组类型的参数呢。

我们首先在Action类中定义数组变量,然后提供setXXX/getXXX方法,这和之前获取参数是一样的,不一样的地方就在于url地址。

public class ParamAction extends ActionSupport {

	private String[] hobby;

	public String[] getHobby() {
return hobby;
} public void setHobby(String[] hobby) {
this.hobby = hobby;
} @Override
public String execute() throws Exception {
System.out.println(Arrays.asList(hobby));
return NONE;
}
}

url地址我们这样写:http://localhost:8080/struts_demo1/param?hobby=baseball&hobby=basketball&hobby=football ,当你的参数名是一样的时候,程序会判断你的参数可能为数组类型,此时我们运行程序然后访问该网址,控制台输出信息。



成功获取到了数组类型参数。

那么接下来便是集合类型参数。

集合又分为简单集合和复杂集合,简单集合,如:List<String> list。简单集合的获取方式和数组一样,提供setXXX/getXXX方法,然后通过相同的变量名进行参数传递。

复杂集合,如:List<User> userList,复杂集合的获取方式就和简单集合不太一样了。我们需要这样去编写url地址:http://localhost:8080/struts_demo1/param?userList[0].sname=zhangsan&userList[1].sname=lisi ,通过userList的下标得到里面的User对象,然后通过.(点)调用对象属性进行赋值,但是尝试过后就会发现,这样做并没有将参数传递成功,这是因为Tomcat版本的不支持,所以我们使用表单来试一下,正常的开发肯定也不会直接通过url地址去传参。

新建一个test.jsp文件。

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<form action="/struts_demo1/param.action" method="post">
<input type="text" name="userList[0].sname" value="张三">
<input type="text" name="userList[1].sname" value="李四">
<input type="submit" value="提交">
</form>
</body>
</html>

然后我们直接访问test.jsp,点提交,控制台输出信息如下。

[User [sname=张三, sid=null, age=null], User [sname=李四, sid=null, age=null]]

这样我们就成功获取到了复杂集合数据。

最后就是Map类型参数了,我们在ParamAction类中添加一个Map集合。

private Map<String, User> map;

public Map<String, User> getMap() {
return map;
} public void setMap(Map<String, User> map) {
this.map = map;
}

那么url地址该如何写呢?http://localhost:8080/struts_demo1/param/map['a']=张三&map['b']=李四 ,但是我们刚才得知,Tomcat版本不支持中括号,同时也不支持单引号,所以直接访问这个地址会报错。所以我们同样使用表单试一下。

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<form action="/struts_demo1/param.action" method="post">
<%--<input type="text" name="userList[0].sname" value="张三">
<input type="text" name="userList[1].sname" value="李四">
--%> <input type="text" name="map['a'].sname" value="张三">
<input type="text" name="map['b'].sname" value="李四">
<input type="submit" value="提交">
</form>
</body>
</html>

然后访问该地址,得到输出信息。

{b=User [sname=李四, sid=null, age=null], a=User [sname=张三, sid=null, age=null]}

成功获取到Map集合类型参数。

SSH开发模式——Struts2进阶的更多相关文章

  1. SSH开发模式——Struts2(第一小节)

    在制定了学习计划的学习过程中,我感觉学习还是很有效率的.很短的时间内,我便学习完了JavaWeb的连接池.DbUtils框架及其一些工具类的使用. 学无止境,学习这些知识还远远不够,所以,在接下来的时 ...

  2. SSH开发模式——Struts2(第三小节)

    struts2框架的知识点,虽然分了几个小节,感觉内容还是挺多的,但是你仅仅是入门了而已,想要进一步地提升自己,你得有一颗持之以恒的学习的心,最后的内容我都将在这篇博客中讲到,所以篇幅可能会有点长,希 ...

  3. SSH开发模式——Struts2(第二小节)

    上一小节已经学会了如何去搭建Struts2的开发环境,该篇博客我们继续深入Struts2,了解Struts2框架的拦截器. 首先对我们在web.xml文件配置的过滤器进行一个源码的分析. 在Strut ...

  4. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:SSH框架(Struts2+Spring+Hibernate)搭建整合详细步骤

    在实际项目的开发中,为了充分利用各个框架的优点,通常都会把 Spring 与其他框架整合在一起使用. 整合就是将不同的框架放在一个项目中,共同使用它们的技术,发挥它们的优点,并形成互补.一般而言,在进 ...

  5. Struts2开发模式漏洞

    当Struts2中的devMode模式设置为true时,存在严重远程代码执行漏洞.如果WEB服务以最高权限运行时,可远程执行任意命令,包括远程控制服务器. 如果为受影响的版本,建议修改配置文件stru ...

  6. struts2的DevMode(开发模式)模式

    本文转自:http://blog.csdn.net/q1054261752/article/details/48687119 在实际应用开发或者是产品部署的时候,对应着两种模式: ① 开发模式(dev ...

  7. SSH整合(Struts2+hibernate+spring)

    1.创建表 create table t_user( id int primary key auto_increment, username varchar(50), password varchar ...

  8. 最新版ssh hibernate spring struts2环境搭建

    最新版ssh hibernate spring struts2环境搭建 最新版spring Framework下载地址:spring4.0.0RELEASE环境搭建 http://repo.sprin ...

  9. 基于Pojo的开发模式(day03)

    上一次的文章讨论到了Spring的设计目标:使得JEE开发更易用. ok,作为一个Java开发人员,应该都知道struts这个框架,不知道是否大家都清楚struts1和struts2的区别. 首先,这 ...

随机推荐

  1. [Go] gocron源码阅读-go语言中的切片接口和类型综合

    // getCommands func getCommands() []cli.Command { command := cli.Command{ Name: "web", Usa ...

  2. C学习笔记(5)--- 指针第二部分,字符串,结构体。

    1. 函数指针(function pointer): 函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调 ...

  3. 日志分析利器Splunk的搭建、使用、破解

    博主对splunk的了解不多,博主的使用目的是为了同步,分析日志.当初的搭建也是为了公司申请牌照需要日志服务器分析日志,顺便自己也对这方面感兴趣就买了本书看了看搭建玩的,后来检查来了博主也给他们演示了 ...

  4. pyquery解析库

    这一篇整理一下pyquery这个解析库.还是菜,若有错误的地方,欢迎大家随时指正.......(come on.......) pyquery:是一个css选择器,再使用时,也需要传入HTML文本来初 ...

  5. 鱼嘤嘤小分队 Alpha冲刺阶段博客目录

    会议记录 周数 链接 主要工作 第六周 第六周链接  确定技术路线 第七周 第七周链接  讨论进展 最近的主要工作: 由于我们的代码能力以及pyhon的基础知识已经网络通信的知识储备是不够的,所以我们 ...

  6. day64_10_8 vue的导入

    一.简介 vue是一个渐进式的js框架.具体介绍查看官网: https://cn.vuejs.org 在vue框架中,有两个文件,当在开发阶段时使用完整版vue,因为有报错信息,而在上市阶段可以使用m ...

  7. OC方法交换swizzle详细介绍——不再有盲点

    原文链接:https://www.cnblogs.com/mddblog/p/11105450.html 如果对方法交换已经比较熟悉,可以跳过整体介绍,直接看常见问题部分 整体介绍 方法交换是runt ...

  8. remote: http basic: access denied fatal: authentication failed for '‘解决办法

    问题描述 由于这个项目代码使用https 进行clone,为什么?因为代码库ssh有问题!fuck! 导致在push代码的时候出现了 remote: http basic: access denied ...

  9. 工具资源系列之给 windows 虚拟机装个 ubuntu

    前面我们已经介绍了如何在 Windows 宿主机安装 VMware 虚拟机,这节我们将利用安装好的 VMware 软件安装 Ubuntu 系统. 前情回顾 虚拟机为我们在 Windows 宿主机体验别 ...

  10. WinSxS目录下文件的清除

    1)McAfee Scanner service 持续高cpu 2)上网查到了,需要看 %deflogdir%目录下的OnDemandScan_Activity.log 3) 打开这个文件,发觉一直在 ...