SSH开发模式——Struts2进阶
在之前我有写过关于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进阶的更多相关文章
- SSH开发模式——Struts2(第一小节)
在制定了学习计划的学习过程中,我感觉学习还是很有效率的.很短的时间内,我便学习完了JavaWeb的连接池.DbUtils框架及其一些工具类的使用. 学无止境,学习这些知识还远远不够,所以,在接下来的时 ...
- SSH开发模式——Struts2(第三小节)
struts2框架的知识点,虽然分了几个小节,感觉内容还是挺多的,但是你仅仅是入门了而已,想要进一步地提升自己,你得有一颗持之以恒的学习的心,最后的内容我都将在这篇博客中讲到,所以篇幅可能会有点长,希 ...
- SSH开发模式——Struts2(第二小节)
上一小节已经学会了如何去搭建Struts2的开发环境,该篇博客我们继续深入Struts2,了解Struts2框架的拦截器. 首先对我们在web.xml文件配置的过滤器进行一个源码的分析. 在Strut ...
- 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:SSH框架(Struts2+Spring+Hibernate)搭建整合详细步骤
在实际项目的开发中,为了充分利用各个框架的优点,通常都会把 Spring 与其他框架整合在一起使用. 整合就是将不同的框架放在一个项目中,共同使用它们的技术,发挥它们的优点,并形成互补.一般而言,在进 ...
- Struts2开发模式漏洞
当Struts2中的devMode模式设置为true时,存在严重远程代码执行漏洞.如果WEB服务以最高权限运行时,可远程执行任意命令,包括远程控制服务器. 如果为受影响的版本,建议修改配置文件stru ...
- struts2的DevMode(开发模式)模式
本文转自:http://blog.csdn.net/q1054261752/article/details/48687119 在实际应用开发或者是产品部署的时候,对应着两种模式: ① 开发模式(dev ...
- SSH整合(Struts2+hibernate+spring)
1.创建表 create table t_user( id int primary key auto_increment, username varchar(50), password varchar ...
- 最新版ssh hibernate spring struts2环境搭建
最新版ssh hibernate spring struts2环境搭建 最新版spring Framework下载地址:spring4.0.0RELEASE环境搭建 http://repo.sprin ...
- 基于Pojo的开发模式(day03)
上一次的文章讨论到了Spring的设计目标:使得JEE开发更易用. ok,作为一个Java开发人员,应该都知道struts这个框架,不知道是否大家都清楚struts1和struts2的区别. 首先,这 ...
随机推荐
- 什么是测试系统工程师(TSE)?
深圳市共创力研发咨询 杨学明/文 TSE(Test System Engineer)简称测试系统工程师,作为系统工程(SE)团队的一员,很多公司目前还没有这样的角色,导致测试部分往往处理弱势,第一,不 ...
- ctr预估论文梳理和个人理解
问题描述 ctr的全称是click through rate,就是预估用户的点击率,可以用于推荐系统的ranking阶段.ctr预估可以理解为给用户的特征.item的特征以及context的特征(比如 ...
- MongoDB 最近遇到的几个小问题
(1)连接数据库时报错 ERROR Topshelf.Hosts.ConsoleRunHost.Run An exception occurred System.TimeoutException: A ...
- Qt在window下的环境变量PATH的配置
Qt在window下的环境变量PATH的配置 路劲: C:\Qt\Qt5.6.0\5.6\mingw49_32\bin C:\Qt\Qt5.6.0\Tools\mingw492_32\bin 发布Qt ...
- (导航页)Amazon Lightsail 部署LAMP应用程序(HA)
Amazon Lightsail 简介: Amazon Lightsail是一个具有易于使用的界面,具有成本效益,快速和可靠的云平台.它是更简单的工作负载,快速部署以及Amazon Web Servi ...
- Java集合源码分析之ArrayList(JDK1.8)
package annoction; import java.util.*; import java.util.function.Consumer; import java.util.function ...
- 洛谷 P1381 单词背诵
洛谷 P1381 单词背诵 洛谷传送门 题目描述 灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的 ...
- 第九周周二总结&&第九周周三计划
周二的主题提取使用LDA模型进行了简单的测试,效果还可以.主要是提取的分词的结果,LDA:随机生成文章各个主题比例,再根据各个主题随机生成词,词与词之间的顺序关系被彻底忽略了,这就是LDA眼中世间所有 ...
- 使用Sourcetree(for windows)建立github同步仓库
回顾Linux作业中用命令行的方式管理本地与远程仓库的过程,原理图如下: 与之前本质相同,但是使用GUI的github管理工具将更为便捷,Sourcetree就是其中之一 1.在Windows下安装g ...
- H5视频、音频不能自动播放,Uncaught (in promise) DOMException: play() failed because the user didn't
错误原因:Chrome的autoplay政策在2018年4月做了更改. 解决办法: 第一步,在chrome浏览器中输入:chrome://flags/#autoplay-policy 第二步,在Aut ...