Struts2
入门
struts 的的简介
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着非常大的变化,但是相对于WebWork,Struts 2的变化很小。
从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:
- 操作(Actions)
- 拦截器(Interceptors)
- 值栈(Value Stack)/OGNL
- 结果(Result)/结果类型
- 视图技术
而Struts2 与传统的MVC框架略有不同,因为它由Action扮演模型的角色,而不是控制器,虽然这样会有一些重叠。
环境准备
首先到Struts2的官网下载框架压缩包,解压后如下所示目录结构。
官网:https://struts.apache.org/
接着在自己的编程 软件上创建一个javaWeb项目
在WEB-INF文件夹下的lib文件夹下面导入struts框架核心的几个架包,因为struts2框架拥有很多的架包,很多我们用不到的就没有必要导入,用到时再导入即可。但是核心架包一定要导入才能是项目真正的能够使用struts2框架。
核心架包
- commons-logging-1.1.x.jar (ASF出品的日志包,struts2使用这个日志包来支持JDK和Log4j的日志记录。)
- freemarker-2.3.x.jar (表现层框架,定义了struts2的可视组件主题,struts2的UI标签的模版,使用FreeMark编写)
- ognl-2.6.x.jar (对象图导航语言(Object Graphic Navigation Language),struts2框架通过其读写对象属性)
- struts2-core-2.x.x.jar (struts2的核心类库)
- xwork.jar ( webwork的核心库,struts2在其上构建)
- commons-fileupload-1.2.1.jar (文件上传组件,2.1.6版本后必须加入此文件)
找这些架包如果是建立的maven项目直接上maven库搜索链接maven会直接下载添加,如果新建的不是maven项目则需要在下载的架包中自己拷贝到项目中。
具体的操作是解压下载的struts2的架包,在如下目录结构中打开apps
打开lib文件夹,将里面的所有jar复制到自己的项目的lib包下面即可使用struts2的基础核心功能。
Struts2的入门小案例
编写一个简单的登录页面跳转,获取pojo返回参数显示在可视页面的例子。
这里新建项目的规则与普通的javaweb项目没有区别,都是在WEB-INF包下面建立网页页面,这里我选择建立的是jsp页面。
在src目录下面建立包,在包里建立相应的java类。
这里需要注意的是在包里建立的pojo类,也就是对应的actiong类,还需要在src目录下建立一个struts.xml文件用来配置pojo类的action。
第一步首先在项目的web.xml文件中配置struts2的拦截器
<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-INF文件夹下建立jsp页面,在src目录下的包下建立pojo类,在src目录下建立struts.xml配置文件。
登录成功跳转页面success.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>用户名:${username}</h1>
<h1>密码:${password}</h1>
</body>
</html>
登录页面login.jsp页面
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="helloWorld" method="post">
<span>用户名</span>
<input type="text" name="username"><br>
<span>密码</span>
<input type="password" name="password"><br>
<button type="submit">登录</button>
</form>
</body>
</html>
java类
import com.opensymphony.xwork2.ActionSupport;
public class helloAction extends ActionSupport {
/**
* 这里的类属性,如果设置为private属性,那就必须要为属性建立set和get方法前端页面才可以顺利取到值。
* 如果设置为public属性,则不提供get和set方法前端也可以顺利取到值。
*/
//变量名要和提价数据的<input/>标签中的name的值是一样的,这样才可以获取。
public String username;
public String password;
@Override
public String execute() throws Exception {
return "success";
}
/*public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}*/
}
struts.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中可以有多个action,其中package的name属性是自己取的一个任意名称,extends属性
继承默认的struts-default -->
<package name="web" extends="struts-default" namespace="/*">
<!-- action中的name属性要和form表单中的action属性的名字一致才能正确运行
class属性的值是这个action所连接的pojo类的路径,代表的是我这个action链接的是 helloAction这一个java类-->
<action name="helloWorld" class="com.yxs.web.helloAction">
<!-- result属性的意思是pojo类方法返回的结果的一个字符串,如果返回的字符串和result中的name属性的值相同
则执行result标签里面的内容,比如跳转到那个页面 -->
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
接下里布置项目在服务器上运行测试。
这里在success.jsp页面获取到用户输入的信息时,可以使用${变量名字},同时也可以使用struts2自带的标签库中的<s:property value=“变量名”/>来实现获取。但需要注意的是在使用这个标签的时候在myeclipse中需要手动导入<%@ taglib prefix=“s” uri="/struts-tags"%>。
在jsp页面中显示变量的方法
1.使用EL表达式:${变量名}
2.使用标签<s:property value="变量名"/>
这里需要说明的是struts2中有一些系列的标签库,可以用来编写前端的页面,但是如果使用了struts2的标签编写前端页面那么就要求后端代码使用struts2框架,有限制不能很好兼容。一般编写前端页面采用的任然是HTML标签和jsp的一些标签项。
<constant name="strtus.action.extension" value="do"></constant>
在struts.xml配置文件中加入上述一行代码,位置是struts标签之内,packe标签之前,加上这一行代码,浏览器的路径去访问该action的时候在其名字后面加上.do即可访问。
同时我们也不一定将所有的struts.xml的配置放到同一个xml文件内,也可以为每一个javaAction类编写一个.xml文件,只需要将如下代码添加到struts.xml配置文件中即可。这也叫做Action的拆分。
<include file="part1.xml"></include>
<!--其中part1是单独写的一个配置javaAction的一个配置文件 -->
Action 接口
概述
Actions是Struts2框架的核心,因为它们适用于任何MVC(Model View Controller)框架。 每个URL映射到特定的action,其提供处理来自用户的请求所需的处理逻辑。
但action还有另外两个重要的功能。 首先,action在将数据从请求传递到视图(无论是JSP还是其他类型的结果)方面起着重要作用。 第二,action必须协助框架确定哪个结果应该呈现在响应请求的视图中。
Struts2中actions的唯一要求是必须有一个无参数方法返回String或Result对象,并且必须是POJO。如果没有指定no-argument方法,则默认是使用execute()方法。
Action的作用
- 封装工作单元
- 数据转移的场所
- 返回结果字符串
创建Action
- 创建一个action类实际上就死创建一个java类,不需要继承任何类或者接口,只是在这个类中必须要有一个名字叫做execute()的方法,该方法的返回值类型是字符串,可以是任意字符串,它的作用只是为了让struts.xml配置文件中对应的Actiong下的result标签接收到这一个结果,进行相应的页面跳转工作。那由此就可见result标签的name属性就一定是和execute()方法返回的字符串是一致的。
- 创建的类实现了Action接口或者继承了ActionSupport类,重写了里面的execute方法。
这里说execute()方法返回一个字符串,可以是自己命名的任意字符串,只要和struts.xml文件中对应的Action类中的result标签的name属性一致就可以死,但是我们也可以直接使用Action 接口中内部定义的五个常量。
Action接口中定义的五个常量:
public static final String ERROR //返回错误
public static final String INPUT //返回输入页面
public static final String LOGIN //返回登录页面
public static final String NONE //返回空,比如上传下载
public static final String SUCCESS //返回成功
Struts2 访问ServletAPI的方法
1.解耦方式
原理:ActionContext是Action执行的上下文,Action的上下文可以看作是一个容器,里面封装了请求(Request)、会话(Session)、Application等,这里面的Request、Session、Application是Map类型的,往里面封装的是键值对,所以这就体现了struts2不与底层servlet Api打交道,那么对很多web的相关对象进行封装,这样可以达到Action与web层解耦。
Map<String,Object> request = ActionContext.getContext().get("request");
//往request里封装数据request.put("name", value);
Map<String,Object> session = ActionContext.getContext().getSession();
//将数据封装到session中session.put("name", value);
这一方法框架并不依赖于Servlet来运行,不具有耦合性。
2.耦合方式
使用ServletActionContext获取, 这种方法获取的都是原生态的ServletAPI
原理:ActionContext是被存放在当前线程中的,获取ActionContext也是从ThreadLocal中获取的。所以在执行拦截器、action和result的过程中,由于他们都是在一个线程中按照顺序执行的,所以可以可以在任意时候在ThreadLocal中获取 ActionContext。 它继承ActionContext,所以ServletActionContext也可以得到HttpServetRequest、HttpServletResponse,它也提供了直接与Servlet相关对象访问的功能,它可以取得的对象
耦合就要依赖于servlet来运行,和获得的属性和以前是一样的,所以就要在项目中导入servlet依赖,不然项目无法运行。
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
ServletContext application = ServletActionContext.getServletContext();
3.实现特定接口(接口注入方式)
**原理:**从servletConfig拦截器的代码中我们可以看到,首先拦截器会判断action是否实现了SessionAware, ServletRequestAware, ServletResponseAware接口,如果实现的话就从context获取相应的session,request,response通过set方法赋值给action属性,这样我们就通过实现接口可以获取到相应的属性来为我们服务了。
javal类一定要实现下面几个相应的接口: implements ServletRequestAware,ServletResponseAware,ServletContextAware 重写它的set方法,这样就可以使用相应的对象了。例如: public void setServletRequest(HttpServletRequest request){ this.request = request; }
推荐使用解耦方式来访问servleAPI这样不依赖servlet。
解耦和耦合方式可以配合着来使用,当面要向一个页面传递东西,或者是需要获得session的时候用解耦的方式来获取一个map往里面存放东西,当要获取数据的时候就使用耦合的方式来获取存到session中的数据,或者是从一个action传递到另一个Action的数据,或者是从一个页面传到一个Action的数据。
数据验证
在进行登录时,为了防止用户输入非法字符或者输入空,就需要对用户提交的数据进行安全验证。
验证是多样的,前台的html,js等就可以实现数据验证,但是有的浏览器可以将前端的验证关闭,从而跳过验证,这是不安全的,这就需要后台也对数据进行一个验证,从而保障数据的安全性。
Struts2框架就提供了一个验证机制或者说一个验证方法。
在ActionSupport中就提供了一个验证方法:
validate()
下面使用演示一个登陆数据后台使用该方法验证的步骤
1.继承ActionSupport类
2.重写其中的validate()方法
//该方法为数据验证方法
@Override
public