您的位置:首页 > 编程语言 > Java开发

【Struts2】Struts2学习(1)简介基本流程、配置

2017-04-28 11:48 429 查看
Struts2简介
 
Struts 英文意思是:支柱、支架。Struts是流行和成熟的基于MVC设计模式的Web应用程序框架。Struts可以帮助我们减少在运用MVC设计模型来开发Web应用的时间。



Struts2的发展历史,Struts2是在Webwork的基础上进行升级的,同时吸收了Struts1的优点,Struts2不是一个全新的框架,因此稳定性、性能等各方面都有很好的保证,同时吸收了Struts1和WebWork两者的优势。
 
Struts2下载地址
http://struts.apache.org/
http://people.apache.org/builds/struts/
 
Struts工作原理图



 
①  首先客户端通过HttpServletRequest向服务器发送一个请求,这个请求会经过一系列的过滤器,如ActionContextCleanUp 以及其他的一些过滤器,最终会被我们的Struts的核心控制器过滤,从struts2.1.3之后,struts核心控制器变为了StrutsPrepareAndExecuteFilter
②  被核心控制器过滤以后,核心控制器会访问ActionMapper 来决定是否要请求某一个action
③  当确定要访问某一个Action后,我们的Struts核心控制器会把控制权委派给我们的ActionProxy(也就是Action的代理)这时候Action代理会通过ConfigurationManager对象来加载Struts.xml核心配置文件。
④  如果在我们的struts.xml中找到了我们要访问的action,则ActionProxy代理会创建一个ActionInvocation实例,action调用实例,在调用Action之前,首先会依次调用拦截器,当把拦截器执行完之后会调用Action,(调用Action会调用Action中的业务处理方法,来完成业务处理),这个方法会返回一个结果,实际是一个字符串,我们通过这个字符串去匹配我们的Result,然后去调度视图返回一个视图或调用另外一个Action。
⑤  当返回视图之后,它并没有去响应用户,这时候还需要把之前执行的拦截器反向再执行一遍,所有拦截器执行完成后,进行最终的响应,通过HttpServletResponse去响应客户端。
 
web工程添加Struts支持
 
1.      首先添加Struts基础的几个jar包至工程lib目录下。
任何MVC框架要与Web框架整合,就要借助于web.xml文件,只有配置在web.xml的Servlet才会被应用加载。对于Struts2框架而言,需要加StrutsPrepareAndExecuteFilter , 

<?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>HelloWorld</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>


2     创建Action类

public class HelloWorldAction extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.println("执行action");
return SUCCESS;
}
}
3. 创建struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default" strict-method-invocation="false">
<action name="helloworld" class="com.meng.action.HelloWorldAction">
<result>/result.jsp</result>
</action>
</package>
</struts>


Struts2配置文件常用配置
 
配置标签
标签详情
package
struts2 使用包来管理它的核心组件Action、拦截器,一个包就是多个Action、拦截器、引用的集合。包的名字需要时唯一的。
常用属性:
name :必填属性,用来指定包的名字。
extends:可选属性,用来指定该包继承其他包,可以继承其他包的action、拦截器。
abstract:设置package的属性为抽象的,抽象的package不能定义action,值为true或false,可以定义一些全局属性,让其他包继承使用。
namespace:可选属性,用来指定该包的命名空间。该命名空间会影响到URL的地址,例如命名为/test 那么访问地址就变为: http://localhost:8080/struts2/test/xxx.action
include
include标签 是struts2中组件化的方式,可以将每个功能模块独立到一个xml配置文件中,然后使用include节点引用
<include file=”xxx.xml”></include>
interceptors
拦截器
属性:
name :拦截器名称
class:拦截器路径
<interceptor name=”xxx” class=”com.xxx.xxx”></interceptor>
interceptor-stack
拦截器栈
default-interceptor-ref
定义默认的拦截器,每个Action都会自动引用,如果Action中引用了其他的拦截器,默认的拦截器失效
<default-interceptor-ref name=”mystack”></default-interceptor-ref>
global-results
全局results配置
<global-results>
   <result name=”input”>/error.jsp</result>
</global-results>
action
name: 如 name=”hello” 则访问的名称是 http://localhost:8080/ProjectName/test/hello.action class:对应的类的路径。
method:调用action中的方法名。
constant
定义常量值:相当于 struts.properties
name:常量名
value:常量值
 
 
访问Servlet API
访问方法
详情
ActionContext类
1.       public static ActionContext getContext();获得当前ActionContext实例。
2.       public Object get(Object key);此方法类似于调用HttpServletRequest的getAttribute(String name)方法。
3.       public void put(Object,Object value);此方法类似于调用HttpServletRequest的setAttribute(String name,Object o)。
4.       public Map getParameters();获取所有的请求参数。类似于调用HttpServletRequest对象的getParameterMap()方法。
5.       public Map getSession();返回一个Map对象,该Map对象模拟了HttpSession实例。
6.       public void setSession(Map session):直接传入一个Map实例,将该Map实例里的key-value对转换成session的属性名-属性值对。
7.       public Map getApplication():返回一个Map对象,该对象模拟了该应用的servlet
10892
Context实例。
8.       public void setApplication(Map application);直接传入一个Map实例,将该Map实例里的key-value对转换成application的属性名-属性值对。
ServletContextAware
ServletRequestAware
ServletResponseAware
实现这三个接口
1.       实现ServletContextAware接口可以直接访问Web应用的ServletContext实例。
2.       实现ServletRequestAware可以直接访问用户请求HttpServletReqeust实例。
3.       实现ServletResponseAware接口可以直接访问服务器响应HttpServletResponse实例。
ServletActionContext
这个类包含一下几个静态方法
static PageContext getPageContext(); 取得PageContext对象。
static HttpServletRequest getRequest();取得HttpServletRequest对象
static HttpServletResponse getResponse();取得HttpServletResponse对象
static ServletContext getServletContext(); 取得ServletContext对象。
 
Action搜索顺序
http://localhost:8080/struts2/path1/path2/path3/student.action
第一步:判断package是否存在,如:path1/path2/path3
package存在
package不存在
第二步:判断action是否存在,如果不存在则去默认namespace的package里面去寻找action。
第三步:如果没有,则报错。
第二步:检查上一级路径的package是否存在(直到默认namespace)重复第一步。path3找不到,找path2,然后path1.
         第三步:如果没有package,则报错。
 
动态方法调用
动态方法调用就是为了解决一个Action对应多个请求的处理,以免action太多。因为默认调用execute方法,所以如果没有动态方法调用,则一个Action默认只处理一种请求。
调用方法
详细使用
指定method属性
<action name=”addAction” method=”add” class=”com.xxx.addAction”><result></result></action>
访问addAction会去调用action类中的add方法。
感叹号方式
不推荐使用这种方式
Struts2.5.2需要开启功能
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
同时还要在package中添加属性
strict-method-invocation="false"
<action name="helloworld" class="com.meng.action.HelloWorldAction">
<result>/result.jsp</result>
<result name="add">/add.jsp</result>
</action>
在Action类中添加add方法,返回add
访问方法: http://localhost:8080/HelloWorld/helloworld!add.action name名+感叹号+方法的名字+后缀
通配符方式
不需要常量<constant …/> 还要在<package>中增加属性
strict-method-invocation="false"
<action name="helloworld_*" method="{1}" class="com.meng.action.HelloWorldAction">
<result>/result.jsp</result>
<result name="add">/{1}.jsp</result>
</action>
helloworld_* 下划线用来分隔,*代表要匹配的内容 http://localhost:8080/HelloWorld/helloworld_add.action
 
指定多个配置文件

<include file=”xxx.xml”></include>


指定编码

<constant name=”struts.il8n.encoding”value=”UTF-8”></constant>
默认Action  访问路径有误,则进入这个页面

<default-action-ref name="index"></default-action-ref>
<action name="index">
<result>/error.jsp</result>
</action>


Struts2后缀
方法1:
<constant name=”struts.action.extension” value=”html”></constant>

方法2:
在struts.properties中
struts.action.extension=action,do,struts2,

方法3:在web.xml中配置

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.xxx </filter-class>
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>do</param-value>
</filter>


接收参数
方法1:使用Action的属性接收参数  get和set方法
首先创建一个表单

<form action="LoginInAction.action" method="post">
<input type="text" name="username" /><br />
<input type="password" name="password" /><br />
<input type="submit" value="提交">
</form>
struts.xml中添加Action的配置
<action name="LoginInAction" method="login" class="com.meng.action.LoginInAction">
<result>result.jsp</result>
</action>
LoginInAction类

public class LoginInAction extends ActionSupport{
private String username;
private String password;
public String login(){
System.out.println(getUsername());
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;
}
}


注意表单的名字需要和Action中的相同,并且在Action中添加set和get方法,这样就可以接收到参数。
方法2:如果属性比较多,我们可以把属性放到一个对象里面,使用DomainModel接收。
创建User类

public class User {
private String username;
private 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;
}
}
改写LoginInAction类

public class LoginInAction extends ActionSupport{
private User user;
public String login(){
System.out.println(user.getUsername());
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
改写表单,注意表单名字的写法,对象.属性名

<form action="LoginInAction.action" method="post">
<input type="text" name="user.username" /><br />
<input type="password" name="user.password" /><br />
<input type="submit" value="提交">
</form>


方法3:使用ModelDriven接收参数,必须实现ModelDriven接口
改写LoginInAction.java

public class LoginInAction extends ActionSupport implements ModelDriven<User>{
/*
* 要使用ModelDriven方法,则set get方法要去掉,
* 而且User对象要实例化
*/
private User user = new User();
public String login(){
System.out.println(user.getUsername());
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
}
改写表单,现在不需要再指定对象的名字。

<form action="LoginInAction.action" method="post">
<input type="text" name="username" /><br />
<input type="password" name="password" /><br />
<input type="submit" value="提交">
</form>


处理传递数据集的情况
例:传递用户的书籍信息
User.java

public class User {
private String username;
private String password;
private List<String> bookList;
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;
}
public List<String> getBookList() {
return bookList;
}
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
}
改写表单

<form action="LoginInAction.action" method="post">
<input type="text" name="username" /><br />
<input type="password" name="password" /><br />
书籍1:<input type="text" name="bookList[0]" /><br />
书籍2:<input type="text" name="bookList[1]" /><br />
<input type="submit" value="提交">
</form>
在LoginInAction中取出书籍数据

public class LoginInAction extends ActionSupport implements ModelDriven<User>{
/*
* 要使用ModelDriven方法,则set get方法要去掉,
* 而且User对象要实例化
*/
private User user = new User();
public String login(){
System.out.println(user.getUsername());
System.out.println(user.getBookList().get(0));
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
}


如果privateList<String> bookList; 改为privateList<User>bookList;
则要改成这种:

书籍1:<input type="text" name="bookList[0].username" />
取出数据:

System.out.println(user.getBookList().get(0).getUsername());


处理结果类型
返回字段
描述
SUCCESS
Action正确的执行完成,返回相应的视图,success是name属性的默认值。
NONE
表示Action正确的执行完成,但并不返回任何视图。
ERROR
表示Action执行失败,返回到错误处理视图。
LOGIN
Action因为用户没有登录的原因没有正确执行,将返回该登录视图,要求用户进行登录验证。
INPUT
Action的执行,需要从前端界面获取参数,INPUT就是代表这个参数输入的界面,一般在应用中,会对这些参数进行验证,如果验证没有通过,将自动返回该视图。
 
INPUT如何进行参数验证,自动返回到视图当中。
方式1:当我们的参数类型不匹配时,会自动返回input,并跳转到LoginInAction
struts.xml
<action name="LoginInAction" method="login" class="com.meng.action.LoginInAction">
<result>/result.jsp</result>
<result name="input">/login.jsp</result>
</action>
User.java中添加 int类型的字段

public class User {
private String username;
private String password;
private int age;
private List<String> bookList;
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;
}
public List<String> getBookList() {
return bookList;
}
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}


如果login.jsp 中输入的参数不是数字则会跳转到login.jsp界面。
添加错误校验:

public class LoginInAction extends ActionSupport implements ModelDriven<User>{
/*
* 要使用ModelDriven方法,则set get方法要去掉,
* 而且User对象要实例化
*/
private User user = new User();
public String login(){
if(user.getUsername() == null || "".equals(user.getUsername())){
this.addFieldError("username","用户名不能为空");
return INPUT;
}
System.out.println(user.getUsername());
System.out.println(user.getBookList().get(0));
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
}
在login.jsp中输出错误信息

<input type="text" name="username" /><s:fielderror style="Color:red;" name="username"></s:fielderror>
也可以重写validate方法
public class LoginInAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public String login(){
System.out.println(user.getUsername());
System.out.println(user.getBookList().get(0));
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
@Override
public void validate() {
if(user.getUsername() == null || "".equals(user.getUsername())){
this.addFieldError("username","用户名不能为空");
}
}
}


处理结果类型
局部结果:将<result/>作为<action/>元素的子元素配置。
全局结果:将<result/>作为<global-result/>元素的子元素配置。
<result name=”xxx”>
<param name=”location”>/{2}.jsp</param>  指定视图的位置
<param name=”parse”>false</param>   是否支持OGNL表达式
</result>

OGNL:Object-Graph Navigation language

<result name=”xxx” type=””></result>
type的默认值是dispatcher,这个类型支持JSP视图技术。


使用 PreResultListener

/*PreResultListener监听器可以在应用转入实际物理视图之前回调该监听器的beforeResult方法*/
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
invocation.addPreResultListener(new PreResultListener() {

@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
System.out.println("返回的逻辑视图的名字为:"+resultCode);
//在返回Result之前加入一个额外的数据
invocation.getInvocationContext().put("extra", new java.util.Date() + "由"+resultCode+"逻辑视图名传入");
}
});

Struts2 异常处理机制
struts2 允许通过 struts.xml文件类配置异常的处理。

我们在登录页面输入用户名和密码两个参数后,用户提交请求,我们自定义几个异常

public String login() throws Exception{
if (user.getUsername().equalsIgnoreCase("user"))
{
throw new MyException("自定义异常");
}
if (user.getUsername().equalsIgnoreCase("sql"))
{
throw new java.sql.SQLException("用户名不能为SQL");
}
if (user.getUsername().equals("li")
&& user.getPassword().equals("meng") )
{
setTip("哈哈,服务器提示!");
return SUCCESS;
}
else
{
return ERROR;
}
}MyException.java
public class MyException extends Exception
{
public MyException()
{
}
public MyException(String msg)
{
super(msg);
}
}struts.xml
<struts>
<package name="default" namespace="/" extends="struts-default" strict-method-invocation="false">
<!-- 定义全局结果映射 -->
<global-results>
<!-- 定义当sql、root两个逻辑异常都对应exception.jsp页 -->
<result name="sql">/exception.jsp</result>
<result name="root">/exception.jsp</result>
</global-results>

<!-- 定义全局异常映射 -->
<global-exception-mappings>
<!-- 当Action中遇到SQLException异常时,
系统将转入name为sql的结果中-->
<exception-mapping exception="java.sql.SQLException" result="sql"/>
<!-- 当Action中遇到Exception异常时,
系统将转入name为root的结果中-->
<exception-mapping exception="java.lang.Exception" result="root"/>
</global-exception-mappings>
<action name="LoginInAction" method="login" class="com.meng.action.LoginInAction">
<result>/result.jsp</result>
<result name="input">/login.jsp</result>
<!-- 定义局部异常映射, 当Action中遇到MyException异常时,
系统将转入name为my的结果中-->
<exception-mapping exception="com.meng.exception.MyException"
result="my"/>
<!-- 定义三个结果映射 -->
<result name="my">/exception.jsp</result>
<result name="error">/error.jsp</result>
<result name="success">/welcome.jsp</result>
</action>
<action name="SecurityCodeImageAction" class="com.meng.action.CheckCodeAction">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">2048</param>
</result>
</action>
</package>
</struts>当系统抛出com.ment.exception.MyException 时,系统返回名为my的逻辑视图
java.sql.SQLException 当Action抛出该异常时,系统返回名为sql的逻辑视图。

java.lang.Exception  当抛出该异常时,系统返回名为root的逻辑视图。

输出异常信息:

<s:property value="exception"/> :输出异常对象本身

<s:property value="exceptionStack"/> 输出异常堆栈信息

示例代码地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息