struts的简介与使用

struts是基于MVC的WEB框架,目前我们在所有项目中,均可以看到它的影子。对于这个神秘的框架,它到底长什么样子呢?希望我的这篇文章,能够带你揭开它神秘的面纱。

本文主要内容:

一:struts的基本使用方法,完成前后端交互。

二:struts的配置:(include、namespace、中文问题、上传最大值、通配符)

三:struts的request、response、session的获取,及ajax请求通过response返回的使用。

四:struts的拦截器interceptor 完成登录验证。

五:调试器、客户端跳转、表单验

六:s:标签:s:iterator遍历、s:form提交、s:check多选按钮、s:radio单选按钮、s:select选择列的使用

一:基本结构:

struts的基本结构是怎样?

1. 以在eclipse中搭建struts为例,创建动态WEB项目,导入struts需要使用到的基本jar包。

2. 在web.xml中配置struts过滤,配置了一个filter过滤器,这个过滤器是引入到了struts的class中,也就是告诉服务器,我这里所过滤出来的请求,以下全部交由struts来处理(其实进入struts中,这个过滤器会去找相应的action完成响应)。

 <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>
	  	<dispatcher>FORWARD</dispatcher>
	  	<dispatcher>REQUEST</dispatcher>
	  	<url-pattern>/*</url-pattern>
  </filter-mapping>

3. 接下来在src目录下(这个目录可以在配置文件中更改,具体如何更改请自行百度,src是struts默认的读取路径)创建struts.xml文件,在该文件中设置action,也就是过滤完的请求来这个配置文件中寻找该何去何从。具体配置如下:例如我们在前端页面访问了localhost:8080/hero这个请求,web.xml过滤给struts.xml来认领,struts.xml去action中匹配hero这个name,然后读取它对应的class类,以及它要访问后台的哪个方法method。

<package>标签制定了该struts的基本情况,name是独一无二的用来区分不同的package,extends默认继承struts-default,

<action>标签代表一个请求过程,包括name代表请求的地址,class和method代表该请求将要访问那个类的那个方法,

<result>代表这个action请求后台完成后,返回的字符也就是对应name中的值,将要跳转到哪个页面中去。

注:一个action可以不用设置result返回值(比如ajax跳转)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="hero" extends="struts-default">	
		<action name="showHero" class="action.HeroAction" method="showHero">
			<result name="show">showHero.jsp</result>
		</action>
	</package>
</struts>

4. 编写相应的后台类与方法,客户端请求该action,完成前后端交互。

在客户端浏览器直接请求某个action个,然后通过配置文件,进入到后台方法中。将后台处理的数据和结果返回到前台页面中进行显示,完成简单的struts跳转:

在action包下新建HeroAction类,并编写showHero方法。该方法中:定义变量msg,并给出get、set方法。方法showHero中,给msg赋值,然后返回show,此时struts.xml接收到了返回的show值,然后根据result的配置跳转到showHero.jsp中。

package action;
public class HeroAction {
	private String msg;
	public String showHero() {
		msg = "nihao";
		return "show";
	}	
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}	
	
}

showHero.jsp中:通过EL表达式

<body>
${msg}
</body>

根据以上配置文件,我们在浏览器中访问:localhost:8080/showHero,就会看到浏览器中显示了nihao。此时struts完成了一次action的请求与响应。这就是简单的struts跳转。

5. 前端到后台:在jsp页面中通过form表单,我们提交一个action请求到后台,struts接收到该请求,并跳转到对应的类方法中,获取到前台传递的数据并进行处理,处理完成后,再通过struts进行跳转。

这里具体以传递对象为例,创建Hero类,设置属性name和price,并设置get、set方法。前台填写name和price,提交到后台,控制台打印前台填写的值。

在addHero.jsp页面中:这里使用的是struts的s:标签。action中addHero!addHero意思是请求addHero这个action中类中的addHero方法。

<%@ taglib prefix="s" uri="/struts-tags"%>
<body>
	<s:form action="addHero!addHero" namespace="hero">
		<s:textfield name="h1.name" label="英雄名称:"></s:textfield>
		<s:textfield name="h1.price" label="英雄血量:"></s:textfield>
		<s:submit value="新增"></s:submit>
	</s:form>
</body>

struts.xml中,

<struts>
	<package name="hero" extends="struts-default">
		<action name="addHero" class="action.HeroAction" >
			<result name="OK">addSuccess.jsp</result>
			<result name="NO">no.jsp</result>
		</action>	
	</package>
</struts>

HeroAction中

package action;

import pojo.Hero;

public class HeroAction {
	private Hero h1;
	public String addHero() {
		System.out.println(h1.getName());
		System.out.println(h1.getPrice());
        return "OK";
	}	
	public Hero getH1() {
		return h1;
	}
	public void setH1(Hero h1) {
		this.h1 = h1;
	}
}

此时浏览器访问addHero.jsp,填写内容,点击提交后,可以在后台控制台中看到传递过来的数据。并且跳转到addSuccess.jsp

6. struts运行原理简单介绍:通过以上举例,可以简单认识了struts是如何工作的,它主要的使命就是完成请求和响应,期间带着前后端交互所带的参数或者对象值。

首先是action的跳转,它的发起的每一次请求其实就是一次request请求,例如我们在form中请求的action地址,首先根据、web.xml配置将该请求交给struts处理,它去读取struts.xml配置,寻找有没有对应的action,找到该action后进入对应的后台,在进入后台方法之前,struts会根据这个类中的属性get、set方法将前台中传递过来的对象值进行匹配,如果一致,则实例化该类的同时,给该类中的属性set注入值,例如上例中的form提交的h1.name,struts先实例化HeroAction这个类,然后读取到前台提交过来的值,对h1进行setName(name),然后setH1(hi),此时跳转到方法中时,h1这个对象已经被赋值了。注意struts的每一次请求action都会重新实例化该类,因为struts是多实例的。

然后通过result服务端跳转返回前台页面时,在后台方法中拥有的对象和属性,只要给了get、set方法,在前台页面中均可以获取到该值。同样也是通过get方法获取到的,在跳到jsp页面时,struts会调用实例的get方法, 获取到实例中的属性,作为参数传递到页面中。

值得注意的是:struts的对象属性在进行前后端交互的时候,必须是在一次请求中才可以使用,如果重新发起了action请求或者在result中设置了发起客户端请求(重定向),那该实例中的属性和对象均不可使用。因为struts的跳转其实是一次request请求。在struts.xml文件值配置的<result>addSuccess..jsp</result>此时是struts发起的服务端跳转,并没有发起新的请求。这个请求是从form表单开始的,完整的请求过程如下: form发起请求---struts处理action----后台HeroAction的addHero()---result服务端跳转到addSuccess..jsp---完成响应,请求结束。

二:struts的配置文件(include、namespace、中文问题、上传最大值、通配符)

1. 我们在开发具体的项目时,一般都会需要用到很多实体很多功能实现类,那如果所有的action都在struts.xml文件中配置的话,将会变得特别难维护和修改。此时可以通过将不同的struts文件分散开来,以<include>标签用引入的方式引入到struts.xml来完成使用。我们在src中新建struts(命名可随意)文件夹然后新建hero.xml文件,按照struts的配置文件标准配置完成action,在src下的struts.xml中(struts默认读取路径是src,可以修改)通过include按照在src下的路径引入该hero.xml文件(strtus/hero.xml)。即可使用,struts会先读取struts.xml文件然后碰到include标签,会按照路径在src下寻找并读取该文件。代码如下:

******************struts.xml文件********************
<struts>
	<constant name="struts.i18n.encoding" value="UTF-8"/>这里是设置的struts的中文编码
	<include file="struts/hero.xml"></include>
</struts>
***********************hero.xml文件**********************
<struts>
	<package name="hero" extends="struts-default" namespace="/hero">
		<action name="addHero" class="action.HeroAction" >
			<result name="OK">addSuccess.jsp</result>
			<result name="NO">no.jsp</result>
		</action>
	</package>
</struts>

2. namespace的使用:项目中会在某个struts的配置文件中添加package的name和package的namespace,name即为该package的唯一标识,不可重复。namespace的使用是用来区分请求地址,添加namespace之后,可以有效地防止action的name命名重复的问题。例如,在本例中,设置了namespace为/hero,则,访问该action的路径就是/hero/addHero。

注1:设置了namespace为/hero之后,result返回时,如果跳转的地址为addSuccess.jsp,默认会去该项目的默认路径下(动态web项目默认的路径就是WebContent)找hero下的addSuccess.jsp。如果不想让它跳转到hero/addSuccess.jsp,可以使用type="redirect"重定向,或者使用绝对路径跳转:/pro/vm/index.jsp,此时会跳转到默认路径(根目录)下的pro下vm下的index.jsp文件。

注2:addHero.jsp在form中action的地址值:<form action:"addHero" namespace:"/hero">此时,提交该form后,struts会首先去namespace为/hero的struts中匹配该action值,如果没有,则再去默认namespace中匹配action的值。而且分为往上寻找的机制,例如action地址为:path1/path2/addHero,则发起请求时,

先去寻找namespace为path1/path2的package,如果有则找addHero,如果没有这个action则404。

如果没找到path1/path2的package,则找path1的namespace,如果有则找action。

如果没有path1,则去未命名(默认的)的namespace中找addHero这个action。找不到的话404。

如果我们在struts.properties设置了只能通过地址栏中的package地址寻找的话,struts只会去namespace为path1/path2的package中找action,找不到则404。

3. struts的中文问题,可以在struts.xml中加上:<constant name="struts.i18n.encoding" value="UTF-8"></constant>

4. 上传文件最大值问题,可在struts.xml中加: <constant name="struts.multipart.maxSize" value="10240000"/>上传文件最大为:10240KB也就是10M

5. 通配符:可以将struts的action的name值设为通配符,如下,name为*product,如果请求的action为addproduct,会找到该action,并跳转到method为add中。

<action name="*product" class="action.ProductAction" method="{1}">
			<result name="input">add.jsp</result>
</action>

三:request、response、session的获取

1. request、response:

可以在后台方法中:通过一下方式获取,通常可以使用response来配合struts完成ajax请求。

HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
 

2. 通过response返回ajax请求值:

主要为使用response.getWriter().write(checkResult)在ajax请求的后台方法中写入响应参数checkResult,并传递给ajax的响应函数中使用。完成判断。

本篇内容不再讲解,博主会单独写一篇文章,通过hibernate访问数据库,并在前台页面完成注册,验证账号是否存在。通过struts进行跳转。

3. session的获取:

通过map的形式:

Map m = ActionContext.getContext().getSession();
m.put("name", product.getName());

此session会贯穿在整个访问会话中,可以通过session并配合struts的拦截器,设置验证用户是否登录。原理就是用户登录之后,在session中存放一个key,并将用户名存在里面,配置action的拦截器,当访问是,在拦截器中验证session中是该key值是否为空,若为空则表示没有登录过。

四:struts的拦截器interceptor:

此拦截器的功能可以理解为servlet中的filter功能,例如我们在addHero这个action中配置了一个struts的拦截器,则访问该action的请求都会被拦截器拦截,去该拦截器中执行一定的业务逻辑,然后根据逻辑告诉action是否继续往下执行还是直接返回结果。

具体配置拦截器如下:

在struts配置文件中,使用<interceptor>声明一个拦截器,并制定该拦截器类所在的路径。

在action中,<interceptor-ref>标签告诉这个action,我要使用这个拦截器,注意:除了自己配置的拦截器之外,一定要引入struts默认的拦截器defaultStack。否则会报错或者不生效。

<struts>
    <package name="basicstruts" extends="struts-default">
        <interceptors>
            <interceptor name="myInter" class="interceptor.MyInter" />
        </interceptors>
        <action name="addHero" class="action.HeroAction" method="addHero">
            <interceptor-ref name="myInter" />
            <interceptor-ref name="defaultStack" />  
            <result name="list">list.jsp</result>
            <result name="login">login.jsp</result>
        </action>
    </package>
</struts>

在配置的拦截器类中:假设此时我们已经登陆了,并且登录时,在session中设置了map.put("userName",userName)的值,在这个拦截器中,将进行是否已经登录的验证,如果登陆了则放行,否则返回登录页面。

public class DateInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception
    {
        ActionContext context = invocation.getInvocationContext();
        Map m = context.getSession();
        String userName = (String)m.get("userName");
        if(userName!=null)
        {
            return invocation.invoke(); //表示拦截器放行通过,继续访问action的方法。
        }
        else
        {
            context.put("errorMsg","请登录!");
            return "login";//返回login,此时struts会执行result中name为login的跳转页面。
        }
    }

五:调试器、客户端跳转、表单验证

1. 调试:导入struts2-config-browser-plugin-2.2.3.1.jar这个包,然后访问localhost8080/struts/config-browser/actionNames也就是项目地址+config-browser/actionNames就可以看到struts中配置的所有action列表。

或者直接在返回的jsp页面中直接添加s:debug,点击它可以看到struts的情况,包括传到该页面的参数对象,session的值等信息。

2. 客户端跳转:可以在struts的result中添加type="redirect",完成跳转的重定向实现客户端跳转。

<action name="add" class="action.HerotAction" method="add">
    <result name="add" type="redirect">add.jsp</result>
</action> 

如果需要传递参数的话可以在跳转的地址中添加:add.jsp?name=${name}或者将参数设置在session中,在前台获取。

3. 表单验证:一般很少用。这里不做介绍了,主要是通过action请求的后台中validate()方法进行访问,还可以通过配置xml进行表单的验证,具体请自行百度学习,这不在赘述。

六:s:标签

在使用struts的s:标签时,需要通过指令引入该标签,即可完成使用。<%@ taglib prefix="s" uri="/struts-tags" %>

1. s:iterator遍历,它的使用很类似与JSTL中的fc:orEach标签。用来遍历输出集合中的值或者对象。使用如下:

访问action并返回一个集合值List<Hero> heros

<table align="center">
    <tr>
        <td>id</td>
        <td>name</td>
        <td>st.index</td>
        <td>st.count</td>
        <td>st.first</td>
        <td>st.last</td>
        <td>st.odd</td>
        <td>st.even</td> 
    </tr> 
    <s:iterator value="heros" var="p" status="st">
        <tr>
            <td>${p.id}</td>
            <td>${p.name}</td>
            <td>${st.index}</td>
            <td>${st.count}</td>
            <td>${st.first}</td>
            <td>${st.last}</td>
            <td>${st.odd}</td>
            <td>${st.even}</td>
        </tr>
    </s:iterator> 
</table>

s:iterator标签进行遍历
value 表示集合、var 表示遍历出来的元素、st 表示遍历出来的元素状态
st.index 当前行号 基0、st.count 当前行号 基1、st.first 是否是第一个元素、st.last 是否是最后一个元素、st.odd 是否是奇数
st.even 是否是偶数

2. s:form提交,

<s:form action="addHero">
  <s:textfield name="hero.name" label="请输入名字:" />
  <s:submit value="Submit" /> 
</s:form>

3.s:check多选按钮,这是一个多选按钮,可以设置默认选中值,

<s:checkboxlist value="selectedHeros" name="hero.id"
    list="heros" listValue="name" listKey="id" />

value:哪些被选中、name:提交到服务端用的名称、list:用于遍历的集合、listValue:显示的checkbox的名称
listKey:checkbox的value

解析:在后台中selectedHerds这个集合对象中我们添加id为1,2的hero对象,在heros中添加id为1,2,3的hero对象,然后传递到这个check中,则value中就是id为1,2的集合也就是默认会选中listKey为1,2的按钮,list为heros代表将1,2,3所有的hero作为按钮展示出来,显示的是listValue为hero的name值,值是listKey为hero的id值,name则是提交这个表单时,提交选中的hero的id值。

4. s:radio单选按钮,使用方法基本与check一致,只是他是单选按钮,不可以多选。

<s:radio name="product.id" value="2" list="products" listValue="name"
    listKey="id" />

5. s:select选择列的使用,选择框的使用。可以设置默认选择值。

<s:select label="英雄列表"
       name="hero.id"
       list="heros"
       listKey="id"
       listValue="name"
       multiple="true"
       size="3"
       value="selectedheros"
/>

name表示:提交到服务端用的名称
list:用于遍历的集合
listKey:每个option的value
listValue:显示的名称
multiple:true表示可以选中多行
size="3"表示默认显示3行
value表示:哪些被选中

有关struts的介绍和使用就到这里

声明:此文章为本人实际学习复习笔记

补充:struts的运行过程分析:

客户端发起一个HTTPServletRequest请求;

这个请求经过WEB.XML配置的filter过滤器进行过滤;

发现FilterDispatcher,然后调用该过滤器,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用具体某个Action;

如果ActionMapper决定需要调用某个Action,FilterDispatcher把处理权限交给ActionProxy来处理;

ActionProxy通过Configuration Manager(适配管理)询问struts的配置文件,找到需要调用的Action类;

找到之后,ActionProxy会创建一个ActionInvocation的实例;

ActionInvocation在调用Action的过程前后,可以进行interceptor拦截器的进行。

当Action执行完毕,ActionInvocation负责根据返回结果寻找struts.xml中的配置中result需要返回的页面。

猜你喜欢

转载自blog.csdn.net/qq_41908550/article/details/83756689