首先咱们先来直接配置,而后再来说原理:
第一步:jar包的引入:
咱们能够到struts2的官网上下载:
http://struts.apache.org/download.cgi#struts2513css
而后解压将里面的app文件夹下的示例war文件解压,将里面的struts.xml复制到咱们新建立的src目录下(特别说一下,struts2最新的Struts 2.5.13版本压缩包里面没有示例的blank示例文件,我是在2.3.34里面得到的)html
配置文件大概是这样的:java
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <action name="hello"> <result> /Hello.jsp </result> </action> </package> </struts>
以上的配置文件是通过个人修改的,因此比较简洁,由于咱们第一步实现action并无那么复杂。web
第二步,咱们须要在web.xml中配置过滤器,将struts组件插入进来。
配置文件大概是这样:apache
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>testStruts2</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <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>
而后咱们在根目录下建立一个jsp文件:浏览器
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> hello<br> </body> </html>
里面不须要太多东西,咱们只是作一个简单的测试。tomcat
而后咱们将项目部署到tomcat中,启动。安全
而后用浏览器访问:
http://localhost:8080/testStruts2/hello
浏览器就会跳转到咱们写好的Hello.jsp页面。服务器
咱们接着讲原理:app
首先,浏览器发出一个url,这个url首先发送到服务器,也就是咱们的tomcat,发到tomcat事后,将交给web.xml,而后进入过滤器,经过过滤器将这个请求发送给StrutsPrepareAndExecuteFilter来处理,
StrutsPrepareAndExecuteFilter调用主配置文件struts.xml中的namespace看是否与namespace吻合,找到与之吻合的package,而后找对应的action的name,而后转到对应的页面。
其实上面过程还省略了一些过程:
就是一个请求到了action的name的时候并不会直接转到咱们的页面,而是会转到action对应的类,
上面的struts省略了这一步,可是struts2帮咱们默认执行了这一个过程,若是咱们补充这个过程的话应该这样:
<action name="hello" class="testStruts2.HelloAction">
package testStruts2; import com.opensymphony.xwork2.ActionSupport; public class HelloAction extends ActionSupport{ public String execute() { return SUCCESS; } }
在struts2的主配置文件action中添加一个class=“”,并在项目的testStruts2中添加一个action类,这个action类能够有三种方法来写,可是都要包含execute方法。
咱们给出剩下的两种action类书写方式:
package testStruts2; import com.opensymphony.xwork2.ActionSupport; public class HelloAction{ public String execute() { return "success"; } }
package testStruts2; import com.opensymphony.xwork2.ActionSupport; public class HelloAction implements Action{ public String execute() { return SUCCESS; } }
以上的两种方法,一个是不继承和实现任何方法,可是包含一个execute方法,返回一个success字符串,另外一个实现Action方法,返回SUCCESS。
Action里面已经封装了一些变量,因此实现这个接口的类能够直接返回SUCCESS,同时咱们还要知道ActionSupport也实现了Action,而且里面还封装了大量的方法,这个之后咱们将慢慢用到。
以上三种action书写方式,建议使用第一种,由于咱们之后将要常用到ActionSupport里面封装的方法。
通过上面这个的Action返回一个success,而后StrutsPrepareAndExecuteFilter,将action里面的result里的页面返回给浏览器。
若是留意的同窗,还会发现咱们从官网下载下来的blank范例里面action里面还有些其余的属性,对就是method。
定义一个action并不必定实现Action接口,同时也能够不执行execute方法,咱们只要将action里面的method属性改成要执行的方法就行,就像这样:
<action name="hello" class="testStruts2.HelloAction" method="ADD">
同时咱们action里面的方法也要改成ADD,可是返回值类型必定要为String
package testStruts2; public class HelloAction { public String ADD() { return "success"; } }
这样对于不一样的请求,咱们能够根据须要在同一个Action类中用不一样的方法处理。
这样能够减小建立Action类,而且安全,可是也会形成一个Action类太过庞杂。
动态方法调用有三种方式,上面的算式一种。
继续咱们来讲第二种:
用“!”叹号方式(不推荐使用)
这种方法怎么使用呢?
<action name="helloadd" class="testStruts2.HelloAction" > <result> /Hello.jsp </result> </action>
就是这样,理论上咱们再Action类中含有execute方法不会产生什么影响,可是若是咱们将Action类中的方法改成String Add()呢?
就会报错,因此就用到可!了,咱们的url地址应该为:
http://localhost:8080/testStruts2/hello/helloadd!ADD
这样就会找到ADD方法了。
可是还要注意一点的是咱们要将动态方法调用打开:
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
这里默认是关闭的,咱们将它改成true就好了。
第三种就是通配符配置了:
首先咱们须要将上面的DMI改成false(不改也能够运行,可是建议改)。
<action name="hello_*" class="testStruts2.HelloAction" method="{1}"> <result> /Hello_{1}.jsp </result> </action>
而后就是这样:用*代替未知的url
这里的{1}表示第一个 * 表明的内容 使用通配符可能有好几个 * ,咱们能够根据*的顺序用{2}{3}…依次表示
http://localhost:8080/testStruts2/hello/hello_ADD.action用这个url来访问咱们的ADD方法,
当咱们须要其余DELETE(删除的时候)
只须要输入http://localhost:8080/testStruts2/hello/hello_DELETE.action
并在Action类里面添加DELETE方法和添加响应的Hello_DELETE.jsp页面。
使用通配符简化了咱们好多的配置,原来须要在配置文件中配置好多个action,如今只须要用通配符就能够解决这些,只须要添加响应的Action类(方法)和jsp页面就好了。
<action name="*_*" class="testStruts2.{1}HelloAction" > <result> /{1}_{2}_hello.jsp</result> </action>
上面的是两个通配符的范例,若是请求是这样:
http://localhost:8080/testStruts2/hello/hello_DELETE.action
它就可以根据{1}找到对应的Action类,根据{2}找到对应的方法。
是否是很简便?(这样的作法叫作约定优于配置)
咱们怎么样用struts接受客户端发过来的参数呢?下面列举四种方法:
①属性参数输入
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <action name="user" class="testStruts1.userAction"> <result> /user.jsp </result> </action> </package> </struts>
上面是配置文件,没什么好说的,和以前大同小异。
咱们接下来看看Action类:
package testStruts1; import com.opensymphony.xwork2.ActionSupport; public class userAction extends ActionSupport{ String username; public userAction() { } public userAction(String username) { super(); this.username = username; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String execute() { System.out.println(username); return SUCCESS; } }
首先这个类要符合javabean的命名规则,咱们再Action类中添加了一个username属性,并含有它的set get方法,并在execute里面将接收到的username输出到控制台来证明实验。
当咱们将项目部署到服务器上后,在浏览器中输入一下URl:
http://localhost:8080/testStruts1/user.action?username=aa
控制台便会将接受到的username参数输出。
咱们能够看到上面使用Action类的属性来接收参数的,struts经过咱们给出的set get 方法帮助咱们完成赋值。
②一样咱们也能够定义一个实体类来来接收这些信息(官方叫DomainModel):
例如
这个是咱们提交的信息:
<form action="login" method="post"> 用户名:<input type="text" name="user.username"><br> 密码<input type="password" name="user.password"><br> <input type="submit" value="登陆"> </form> /*input里面必定要使用user.username和user.password和实体类对应,或者使用struts2提供的标签,不然会出错(不要问我是怎么知道的 哭脸.jpg)*/
这个是实体类:
package entity; public class User { String username; String password; 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; } }
package testStruts1; import com.opensymphony.xwork2.ActionSupport; import entity.User; public class userAction extends ActionSupport{ User user;//不须要new对象,struts2帮咱们完成了 public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String execute() { if(user.getUsername().equals("username")&&user.getPassword().equals("password")) { return SUCCESS; } return ERROR; } }
/*struts.xml*/ <action name="login" class="testStruts1.userAction"> <result name="success"> /user.jsp </result> <result name="error"> /error.jsp </result> </action>
③还有一种使用DTO(date transfer object)数据传输对象来进行传输。
这种方式主要是应对提交的参数和咱们的实体对象不匹配的情况:
好比用户注册的时候会输入第二次密码来进行确认,咱们将接受两个密码,因此在这个类中咱们接收三个参数:username ,password,confirmPassword。
而后在Action类的execute方法中使用DTO对象来对User对象进行赋值:
User user = new User();//这里就须要咱们实例化了,由于struts实例化的机会被下面的玩意抢了。 DTO dto ; public String execute(){ user.setUserName(dto.getUserName()); user.setUserPassword(dto.getUserPassword()); //后面再利用user实例来进行一系列的操做。 }
固然如今咱们有更为先进的技术就是咱们彻底能够用js来在客户端确认是否相同,而后将数据传输过来。
④还有一种叫方法:ModelDriven
public class userAction extends ActionSupport implements ModelDriven<User>{ User user = new User();//这里须要本身new对象 @Override public User getModel() { return user; } public void setUser(User user) { this.user = user; } public User getModel() { return user; } public String execute() { if(user.getUsername().equals("username")&&user.getPassword().equals("password")) { return SUCCESS; } return ERROR; } }
就是这样,实现ModelDriven接口,并实现getModel方法,直接得到这个模型对象user。怎么实现这样的原理的呢?
是经过一个缺省的拦截器ModelDrivenInterceptor这里面判断一个Action对象是否实现ModelDriven,若是实现就返回这个User对象,并将User对象push到valueStack中(valueStack后边介绍)。