struts2-学习笔记(三)

时间:2023-03-09 08:52:03
struts2-学习笔记(三)

Struts2 学习笔记(三)

1.ognl概述:

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

OGNL相对其它表达式语言具有下面几大优势:

1、支持对象方法调用

如xxx.doSomeSpecial();

2、支持类静态的方法调用和值访问

表达式的格式:

@[类全名(包括包路径)]@[方法名 |  值名],例如:

@java.lang.String@format('foo %s', 'bar')

或@tutorial.MyConstant@APP_NAME;

设置 struts.ognl.allowStaticMethodAccess=true

3、支持赋值操作和表达式串联,

如price=100, discount=0.8,calculatePrice(),这个表达式会返回80;

4. 访问OGNL上下文(OGNL context)和ActionContext

5、操作集合对象。

Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map的接口.

2. ognl简单操作代码示例:

<body>

<!-- JSTL:c:out 功能和 s:property暂时任务输出内容到页面上 .property的value属性的取值就是一个OGNL表达式-->

<br/>----------------ognl对象的普通方法调用-----------------------<br/>

<s:property value = "'itheima'.length()"/><br/>

<s:property value = "'itheima'.charAt(1)"/><br/>

<br/>----------------ognl对象静态方法调用-----------------------<br/>

<s:property value = "@java.lang.Integer@MAX_VALUE"/>

<s:property value = <a
href="mailto:\" @java.lang.string@valueof(123)\"="">" >"@java.lang.String@valueOf(123)"/>

</body>

注意调用静态方法需要在struts.xml文件中打开开关

<struts>

<constant name="struts.devMode" value="true" />

<constant name="struts.ognl.allowStaticMethodAccess" value="true" />

</struts>

页面显示结果:

struts2-学习笔记(三)

3. ValueStack&ActionContext(非常重点:值栈)

这一部分理解起来少有难度,不过通过画图可以比较清晰的了解其内部结构:废话不多说:上图:

struts2-学习笔记(三)struts2-学习笔记(三)

struts2-学习笔记(三)

4. Ognl取 contextMap中存入数据

request:请求范围的数据。即ServletRequest中的那个Map

parameters:请求参数的数据。即request.getParameter Map得到

application:应用范围的数据。即ServletContext中的那个Map

session:会话范围的数据。即HttpSession中的那个Map

attr:也是一个Map。会从以下Map中依次搜索:request、session、application

Demo1Action

package com.itheima.action;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.util.ValueStack;

public class Demo1Action extends ActionSupport{

private String username = "崔召金";

private String p ="actionp";

public String getP() {

return p;

}

public void setP(String p) {

this.p = p;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String execute() throws Exception

{

ServletActionContext.getRequest().setAttribute("p", "rp");

ServletActionContext.getRequest().getSession().setAttribute("p", "sp");

ServletActionContext.getServletContext().setAttribute("p", "ap");

上面指定范围内添加元素

//ServletActionContext.getRequest().setAttribute("p", new Object());

ValueStack vs = ActionContext.getContext().getValueStack();

System.out.println(vs);

return SUCCESS;

}

}

Jsp页面contextMap.jsp

<body>

<br/>取contextMap中的根中(List类型的,实际类型CompoundRoot)的数据.<br/>

<s:property value="locale"/>

<!-- value="username"的涵义:从根中的栈顶开始,对每个对象搜索他的getUsername()方法,找到为止 -->

<br/>取contextMap中的其他的数据(非根中的).<br/>

<s:property value="#request"/><br/>

动作中的:<s:property value="p"/><br/>

请求范围:<s:property value="#request.p"/><br/>

会话范围:<s:property value="#session.p"/><br/>

应用范围:<s:property value="#application.p"/><br/>

<!-- 依次请求\会话范围\应用范围查找名称为p的对象 -->

attr:<s:property value="#attr.p"/><br/>

<!-- 显示出来的东西并不是contextMap中所有的东西,只是大部分 -->

<s:debug></s:debug>

</body>

5. ValueStack的常用方法

public class Demo2Action extends ActionSupport{

public String demo1() throws Exception {

ValueStack vs = ActionContext.getContext().getValueStack();

---------------setValue()方法

vs.setValue("p", "p1");//p是一个ONGL表达式.不是以#开头,访问的是root中的对象,从栈顶依次搜索对象的setP()方法,发现没有,报错。

vs.setValue("#p", "p1");//第一个参数是ONGL表达式,以#开头,访问的是contextMap,因此向Map中添加数据。map.put("p","p1");

vs.setParameter("#p", "p2");//看似与setValue类似

---------------set(String key, Object o)

vs.set("p3", "p33");//第一个参数不是ONGL表达式,只是一个普通的字符串.

//监测根中栈顶对象是不是一个Map,如果不是,创建一个Map对象的实例,map.put("p","p3"),把Map压入栈顶

vs.push(new Date());

vs.set("p3", "p44");

//为演示ValueStack.findValue()做准备数据

//vs.set("p", "p1");//向栈顶放Map,key=p value=p1

//vs.setValue("#p", "p2");//向contextMap中放数据

return super.execute();

}

}

setValue("p", "p1")

p是一个ONGL表达式.不是以#开头,访问的是root中的对象,从栈顶依次搜索对象的setP()方法,发现没有,报错。

setValue("#p", "p1")

第一个参数是ONGL表达式,以#开头,访问的是contextMap,因此向Map中添加数据。map.put("p","p1");

setParameter("#p", "p2");

看似与setValue类似

vs.set("p3","p33");

vs.push(new Date());

vs.set("p3", "p44");

//第一个参数不是ONGL表达式,只是一个普通的字符串.

//监测根中栈顶对象是不是一个Map,如果不是,创建一个Map对象的实例,map.put("p","p3"),把Map压入栈顶

//为演示findValue()做准备数据

vs.set("p", "p1");//向栈顶放Map,key=p value=p1

//vs.setValue("#p","p2");向contextMap中放数据

String s1 = (String)vs.findValue("p");//参数是一个OGNL表达式

//如果从栈顶找不到key为p的数据,或者getP()的方法,就从contextMap中找了。不建议

String s2 = (String)vs.findValue("#p");//参数是一个OGNL表达式

out.write("s1="+s1+"<br/>");

out.write("s2="+s2+"<br/>");

Strings1=vs.findString("#p")

out.write(s1);

//获取到的就是一个String,框架已经给你转换好了

6. 常见的标签(ognl的其他使用方式)

Struts中的EL表达式:

Action类中

public class ELDemo1Action extends ActionSupport {

public String execute() throws Exception {

ValueStack vs = ActionContext.getContext().getValueStack();

ServletActionContext.getRequest().setAttribute("p", "rp");

ServletActionContext.getRequest().getSession().setAttribute("p", "sp");

ServletActionContext.getServletContext().setAttribute("p", "ap");

return SUCCESS;

}

Jsp页面中

<br/>--------用OGNL来取-----------<br/>

OGNL_REQUEST:<s:property value="#request.p"/><br/>

OGNL_SESSION:<s:property value="#session.p"/><br/>

OGNL_APPLICATION:<s:property value="#application.p"/><br/>

<br/>--------用EL来取-----------<br/>

OGNL_REQUEST:${requestScope.p}<br/>

OGNL_SESSION:${sessionScope.p}<br/>

OGNL_APPLICATION:${applicationScope.p}<br/>

EL表达式中一个特殊的问题:

${p}

画图分析:

<br/>------------EL取数据特殊问题:Struts2对EL的功能进行了改写<br/>

${p}从request范围中取数据<br/>

--%>

${p}<br/>

我们总以为会在域范围内按顺序查找,其实不然:

图示如下:

struts2-学习笔记(三)struts2-学习笔记(三) struts2-学习笔记(三)

struts2-学习笔记(三)

struts2-学习笔记(三)struts2-学习笔记(三)

struts2-学习笔记(三)

Struts通用标签:

<s:property/>

什么都不写,输出的是栈顶对象

<s:property value="username"/>

从栈顶开始搜索属性username

<s:property value="[0]"/>

输出根栈中的所有元素

<s:property value="[1]"/>

输出根栈中的除栈顶的所有元素

<s:property value="[0].top"/>

输出根栈中的第一个元素

<s:property value="gender"/>

<s:property value="#gender"/>

<!-- 内部原理:调用的是ValueStack的findValue方法 -->

不提倡第一种写法。容易混乱

<s:property value="'<hr/>'" default="木有"/><br/>

转义符号,输出字符串

<s:set value="username" var="name"></s:set>

<s:set value="username" var="name" scope="session"></s:set>

<s:set value="'安康'" var="ppp" scope="action"></s:set>

<s:property value="#request.ppp"/>

赋值操作:var为变量名字,value为被赋的值

<!-- 如果范围为action,第一放到了request请求范围中,第二放到了contextMap中 -->

<s:push value="'abcdefg'">

</s:push>

s:push把String类型的对象压入栈顶,接着弹栈.要想看:需要把s:debug放入标签内部

<br/>----------------s:bean

<s:bean name="java.util.Date"></s:bean>

<!--

该标签设计有些不友好:

name:指定要实例化的JavaBean的类全名。如果是class就好了。

var:指定的话,放到contextMap和request范围中

不指定的话,放入栈顶,遇到结束标签,弹栈

-->

<s:action name="action2" executeResult="true"></s:action>

<!-- s:action会把另外一个动作的结果包含到当前页面中 -->

<s:iterator varlue = “” var = “”>的使用

<s:iterator value="ps">

<tr>

<td>${nickname}</td>

<td><s:property value="gender"/></td>

<td>${salary}</td>

</tr>

</s:iterator>

不指定var:就相当于把当前遍历对象压入了根栈的栈顶

<s:iterator value="ps" var="p">

<tr>

<td>${p.nickname}</td>

<td><s:property value="#p.gender"/></td>

<td>${p.salary}</td>

</tr>

</s:iterator>

指定var:就相当于把当前遍历对象存到了contextMap中(建议)

<!-- 指定var:就相当于把当前遍历对象存到了contextMap中(建议)

<s:iterator value="ps" var="p" status="s">

<tr class="<s:property value="#s.odd?'odd':'even'"/>">

<td>${p.nickname}</td>

<td><s:property value="#p.gender"/></td>

<td>${p.salary}</td>

</tr>

</s:iterator>

status:指向一个对象,记录着当前遍历元素的一些属性。他有以下属性(放到了contextMap中)

int getCount

int getIndex

boolean isEven

boolean isOdd==getOdd

boolean isFirst

boolean isLast

<br/>----------------s:if else if(重点)------------------<br/>

<s:set value="'C'" var="grade"></s:set>

<s:if test="#grade=='A'">

优秀

</s:if>

<s:elseif test="#grade=='B'">

良好

</s:elseif>

<s:else>

尚需努力

</s:else>

<!-- s:param的value取值是一个OGNL表达式 -->

<s:url action="action2" var="url">

<s:param name="username" value="'哦也'"></s:param>

<s:param name="password" value="123"></s:param>

</s:url>

<a href="<s:property value='#url'/>">猛点</a>

<s:debug></s:debug>

<s:url action = “”,var = “url”>使用方式>

<s:url action="action2" var="url">

<s:param name="username" value="'哦也'"></s:param>

<s:param name="password" value="123"></s:param>

</s:url>

<a href="<s:property value='#url'/>">猛点</a>

<s:debug></s:debug>

<!-- s:param的value取值是一个OGNL表达式 -->

如果<constant name="struts.action.extension" value="do"></constant>

那么在使用<s:property value= “#url”时,自动加.do

<br/>--------OGNL的投影查询----------<br/>

<table border="1">

<tr>

<th>姓名</th>

</tr>

<!-- ps.{nickname} ---List<String>  var=“p”引用的是一个String类型的,就代表着匿名  -->

<s:iterator value="ps.{nickname}" var="p">

<tr>

<td><s:property value="#p"/></td>

</tr>

</s:iterator>

</table>

<br/>--------OGNL的过滤----------<br/>

<s:iterator value="ps.{?#this.salary>8000}" var="p">

<tr>

<td>${p.nickname}</td>

<td><s:property value="#p.gender"/></td>

<td>${p.salary}</td>

</tr>

</s:iterator>

利用OGNL创建List和Map(很重要)

<br/>-----创建List-------<br/>

<s:iterator value="{'a','b','c'}" var="s">

<s:property/><br/>

</s:iterator>

<br/>-----创建Map-------<br/>

<s:iterator value="#{'a':'aaa','b':'bbb','c':'ccc'}" var="me">

<s:property value="#me.key"/>=<s:property value="#me.value"/><br/>

</s:iterator>

规律:

通用标签:

value属性:大部分都是OGNL表达式(90%)

UI标签:表单有关

value属性:大部分都不是OGNL表达式(90%)

如果要当做OGNL表达式对待:使用%{}

如果要把OGNL当做字符串对待:使用'';

7. 常见的UI标签

<s:form action="regist" namespace="/student">

<s:token/>

<s:textfield name="username" label="用户名" requiredLabel="true"/>

<s:password name="password" label="密码" requiredLabel="true"/>

<s:textfield name="birthday" label="出生日期"></s:textfield><s:fielderror fieldName="birthday"></s:fielderror>

<s:textarea name="description" label="简介" rows="3" cols="38"></s:textarea>

<s:checkbox name="married" label="已婚"></s:checkbox>

<s:radio name="gender" list="#{'male':'男性','female':'女性'}" label="性别" value="{'male'}"></s:radio>

<s:checkboxlist name="hobby" list="#{'eat':'吃饭','sleep':'睡觉','java':'学Java'}" label="爱好" value="{'java','eat'}"></s:checkboxlist>

<s:select name="province" list="#{'BJ':'北京','SD':'山东省'}" label="省份" value="{'SD'}"></s:select>

<s:submit align="center" value="保存"></s:submit>

</s:form>

8. 常见主题操作:

主题: 为了让所有的 UI 标签能够产生同样的视觉效果而归集到一起的一组模板. 即风格相近的模板被打包为一个主题

1、simple: 把 UI 标签翻译成最简单的 HTML 对应元素, 而且会忽视行标属性

2、xhtml: xhtml 是默认的主题. 这个主题的模板通过使用一个布局表格提供了一种自动化的排版机制.(默认值)

3、css_xhtml: 这个主题里的模板与 xhtml 主题里的模板很相似, 但它们将使用 css 来进行布局和排版

4、ajax: 这个主题里的模板以 xhtml 主题里德模板为基础, 但增加了一些 Ajax 功能.

struts2-学习笔记(三)struts2-学习笔记(三)总结:

当from 表单的主题是simple的情况下,需要自己设置回显的标记<s:filederror/>

在默认的主题下

显示效果如下:

struts2-学习笔记(三)

9. 如何处理表单重复提交

1.Redirect after post :可以让刷新的页面时地址栏重定向之后的静态的页面。

2.第二种方式

原理分析:有一个GUID 类产生随机码,分别赋值给表单中的和session中的token。当页面提交后,将request.getParameter 得到的

Token和session 中token进行比对:

如果想当,提交数据请求:

然后将session中的token删除

不相等,报错。

struts2-学习笔记(三)

struts2-学习笔记(三)

3.第三种方式(提交用户体验)

struts2-学习笔记(三)

10.Spring入门

1. Spring入门:(java环境下的配置)

首先Spring作为一个框架,内嵌的一个抽象的大数据机构是一个大的Map;这是一个大容器。Key, value 相对应

而后,Spring容器中包含一个名为application.xml的文件。里面初始化了一些Spring需要的类和接口,初始化后(默认单例初始化),这些类被装入了大map中。

struts2-学习笔记(三)

Sring入门环境搭建:

业务层和数据层交互的代码结构如下:

struts2-学习笔记(三)

1.考jar包

Spring.jar

Commons-logging.jar

2.application.xml文件的配置

struts2-学习笔记(三)

3.写各种类

SpringTest.java

struts2-学习笔记(三)

4.写测试类,注意到如上的sping环境的搭建实在java环境的模式下运行测试的。

package com.itheima.test;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.itheima.service.BusinessService;

public class SpringTest {

@Test

public void test1(){

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

BusinessService s1 = (BusinessService) ac.getBean("businessService");

BusinessService s2 = (BusinessService) ac.getBean("businessService");

s1.regist();//默认情况下ac得到bean是单例。所以执行的结构是相同的。

s2.regist();

}

}

2. Web环境下的配置。

1.配置文件的部署

struts2-学习笔记(三)

Web.xml文件中的配置

在web.xml文件的需要注册监听器。将applicationContext.xml文件找到

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

Jsp页面中执行如下的代码:

struts2-学习笔记(三)

运行效果是一样一样的。

11. Spring和struts2开发环境的搭建:

Struts2中的Action及Result对象都是由一个叫做ObjectFactory来创建和管理的。

Struts2诞生要比Spring晚,所以Struts2知道Spring的运作,于是Struts2提供了集成Spring的插件struts2-spring-plugin-2.3.15.3.jar。

注:在Struts2的default.properties中有介绍关于替换掉ObjectFactory的内容,比如更改配置参数:struts.objectFactory = spring,于是乎很多文档都要求在struts.xml中通过<constant/>元素来更改该参数,但这不是必须的,因为struts2-spring-plugin-2.3.15.3.jar中的struts-plugin.xml中已经做好了这样的配置,因此只需要把jar包搞过来即可。

常量struts.objectFactory.spring.autoWire = name指定按名字装配。

此时,Struts2交给了org.apache.struts2.spring.StrutsSpringObjectFactory来创建Action,同时会从Spring拉取需要的对象。

具体使用:a

1. 第一种方式

一、搭建Struts2(2.3.15.3)的环境

a、在JavaWeb应用的lib目录中拷贝运行Struts2必要的jar包。

b、在web.xml中配置核心过滤器

<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>

c、在WEB-INF/classes目录下建立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>

<constant name="struts.devMode" value="true" />

<package name="p1" extends="struts-default">

<action name="test" class="com.itheima.actions.TestAction"/>

</package>

</struts>

d、分别建立TestAction,调用一个XxxService的某个方法,编写XxxServiceImpl的实现。

-------------------------------------------------------------------------

TestAction:

package com.itheima.actions;

import com.itheima.service.XxxService;

public class TestAction {

private XxxService xxxService;

public void setXxxService(XxxService xxxService) {

this.xxxService = xxxService;

}

public String execute(){

xxxService.doSomething();

return "none";

}

}

-------------------------------------------------------------------------

XxxService

package com.itheima.service;

public interface XxxService {

void doSomething();

}

-------------------------------------------------------------------------

package com.itheima.service.impl;

import com.itheima.service.XxxService;

public class XxxServiceImpl implements XxxService {

public void doSomething() {

System.out.println("我做了,怎么着?");

}

}

启动后访问http://localhost:8080/YourAppName/test.action会包空指针异常

二、在Struts2中集成Spring:主要用到Spring的Bean装配

1、拷贝Spring(2.5.6)所需jar包及Struts2与Spring的插件包:

Spring.jar;struts2-spring-plugin-2.3.15.3.jar

2、配置监听器完成Spring容器的初始化

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

3、在WEB-INF目录下建立applicationContext.xml的Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean name="xxxService" class="com.itheima.service.impl.XxxServiceImpl"/>

</beans>

启动后访问http://localhost:8080/YourAppName/test.action,一切正常。

2. 第二种方式:

主要思路是Struts2中的Action实例也交给Spring容器进行管理,在Spring配置时就给Action的属性进行装配。而Struts2中执行某个动作时要找某个动作类,此时把class指定为Spring中的Bean的名称既可以找到。稍作配置如下:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean name="xxxService" class="com.itheima.service.impl.XxxServiceImpl"/>

<bean name="testAction" class="com.itheima.actions.TestAction" scope="prototype">

<property name="xxxService" ref="xxxService"></property>

</bean>

</beans>

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>

<constant name="struts.devMode" value="true" />

<package name="p1" extends="struts-default">

<action name="test" class="testAction"/>

</package>

</struts>

注:如果学员学过Spring,可以看看StrutsSpringObjectFactory的源代码