Model:模型:主要用于数据和业务的处理。View:视图:用于数据的显示Controller:控制器:用于进行流程控制
MVC设计模式的特点:
|
所有 XML 文档中的文本均会被解析器解析。 只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。 PCDATAPCDATA 指的是被解析的字符数据(Parsed Character Data)。 XML 解析器通常会解析 XML 文档中所有的文本。 当某个 XML 元素被解析时,其标签之间的文本也会被解析: <message>此文本也会被解析</message>
解析器之所以这么做是因为 XML 元素可包含其他元素,就像这个例子中,其中的 <name> 元素包含着另外的两个元素(first 和 last): <name><first>Bill</first><last>Gates</last></name>
而解析器会把它分解为像这样的子元素: <name>
<first>Bill</first>
<last>Gates</last>
</name>
转义字符非法的 XML 字符必须被替换为实体引用(entity reference)。 假如您在 XML 文档中放置了一个类似 "<" 字符,那么这个文档会产生一个错误,这是因为解析器会把它解释为新元素的开始。因此你不能这样写: <message>if salary < 1000 then</message>
为了避免此类错误,需要把字符 "<" 替换为实体引用,就像这样: <message>if salary < 1000 then</message>
在 XML 中有 5 个预定义的实体引用:
注释:严格地讲,在 XML 中仅有字符 "<"和"&" 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。 CDATA术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。 在 XML 元素中,"<" 和 "&" 是非法的。 "<" 会产生错误,因为解析器会把该字符解释为新元素的开始。 "&" 也会产生错误,因为解析器会把该字符解释为字符实体的开始。 某些文本,比如 JavaScript 代码,包含大量 "<" 或 "&" 字符。为了避免错误,可以将脚本代码定义为 CDATA。 CDATA 部分中的所有内容都会被解析器忽略。 CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束: <script>
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then
{
return 1;
}
else
{
return 0;
}
}
]]>
</script>
在上面的例子中,解析器会忽略 CDATA 部分中的所有内容。 关于 CDATA 部分的注释:CDATA 部分不能包含字符串 "]]>"。也不允许嵌套的 CDATA 部分。 标记 CDATA 部分结尾的 "]]>" 不能包含空格或折行。 |
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。 DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。 内部的 DOCTYPE 声明假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中: <!DOCTYPE 根元素 [元素声明]>
带有 DTD 的 XML 文档实例(请在 IE5 以及更高的版本打开,并选择查看源代码): <?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
在您的浏览器中打开此 XML 文件,并选择“查看源代码”命令。 以上 DTD 解释如下:!DOCTYPE note (第二行)定义此文档是 note 类型的文档。 !ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body" !ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型 !ELEMENT from (第五行)定义 frome 元素为 "#PCDATA" 类型 !ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型 !ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型 外部文档声明假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中: <!DOCTYPE 根元素 SYSTEM "文件名">
这个 XML 文档和上面的 XML 文档相同,但是拥有一个外部的 DTD: (在 IE5 中打开,并选择“查看源代码”命令。) <?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
这是包含 DTD 的 "note.dtd" 文件:.dtd为文件后缀 <!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
为什么使用 DTD?通过 DTD,您的每一个 XML 文件均可携带一个有关其自身格式的描述。 通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。 而您的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。 您还可以使用 DTD 来验证您自身的数据。 |
- 运行时生成对象实例
- 运行时调用对象方法
- 运行时更改对象属性
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象
- 在运行时判断一个类所具有的方法和属性。
- 在运行时调用任意一个对象的方法
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
/*
* 使用反射就是使用未知的类和未知的方法,所谓未知就是"com.reflectionDemo.Car"
* 和"run" 这两个字符串可以在配置文件中读取
*/
//这一行代表的是拿到对应的类名,而不是实例
Class<?> cls= Class.forName("com.reflectionDemo.Car");
//类的完整名包括包名,否则抛异常
//创建一个实例
Object object=cls.newInstance();
//获取实例的方法,注意这里并没有调用
Method method= cls.getMethod("run");
//调用这个方法,参数就是实例本身
method.invoke(object);
System.out.println("----------------");
Class<?> circleClass=Class.forName("com.reflectionDemo.Circle");
Object object3= circleClass.newInstance();
//
方法名 方法形参 当前对象 实际参数
(多个用逗号分隔)
circleClass.getMethod("setRadius",double.class).invoke(object3, 10);
Object object2= circleClass.getMethod("calcArea").invoke(object3);
System.out.println(object2);
}
}
|
package com.reflectionDemo;
public class Car implements Vehicle {
public Car() {
}
private double price = 123455.00;
public double getPrice() {
return price;
}
public void run() {
System.out.println("汽车在行驶!");
}
private void say() {
System.out.println("haha!");
}
}
|
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestDemo {
public static void main(String[] args) throws Exception {
Class<?> cls= Class.forName("com.reflectionDemo.Car");
Object object=cls.newInstance();
//测试获取私有方法
Method method= cls.getDeclaredMethod("say");
method.setAccessible(true);
//true值表明反射的对象应当压制java语言访问检查时
method.invoke(object);
//测试获取私有字段
Field field= cls.getDeclaredField("price");
field.setAccessible(true);//true值表明反射的对象应当压制java语言访问检查时
double price=field.getDouble(object);
//调用这个方法,参数就是实例本身
System.out.println("价格是:"+price);
}
}
|
- 表现层单一:只支持jsp而不支持FreeMark、Velocity的视图技术
- 对servletAPI的依赖性很强
- 不利于代码的重用,耦合性很强
<%@ taglib uri="/struts-tags" prefix="s" %>
<div>
<%--显示Struts Action中message属性内容,这就是ognl(对象导航图语言)表达式,等价于${message}--%>
<s:property value="message"/>
</div> |
package stu.action;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import stu.biz.ClassesBiz;
import com.opensymphony.xwork2.ActionSupport;
@Component("classesAction")
public class ClassesAction extends ActionSupport {
@Autowired
private ClassesBiz classesBiz;
private Student student;
public Student getStudent() {//通过getter来推送数据
return student;
}
public void setStudent(Student student) {//通过setter来为属性赋值
this.student = student;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
|
ActionContext ac=ActionContext.
getContext
();
Map<String, Object> application=ac.getApplication();
Map<String, Object> session=ac.getSession();
Map request=(Map)ac.get("request"); //没有getRequest()方法 |
分别实现
org.apache.struts2.interceptor.RequestAware,该接口只有
setRequest这个方法要实现
org.apache.struts2.interceptor.SessionAware,该接口只有
set
Session
这个方法要实现
org.apache.struts2.interceptor.ApplicationAware,该接口只有
set
Application
t这个方法要实现
@Override
public void setRequest(Map<String, Object> arg0) {
}
|
ServletActionContext.
getRequest
();
ServletActionContext.getRequest().getSession();
ServletActionContext.getResponse();
ServletActionContext.getContext().getApplication(); |
也可以实现org.apache.struts2.interceptor.ServletRequestAware;接口
也可以实现
org.apache.struts2.interceptor.ServletResponseAware;
接口 也可以实现 org.apache.struts2.util.ServletContextAware; 接口 |
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML>
<html>
<head>
<title></title>
</head>
<body>
<h1>用户登录</h1>
<s:fielderror/>
<form action="/Stu/userLogin" method="post">
<label for="userName">用户名:</label><input type="text" id="userName" name="userName"/><br/>
<label for="password">密码:</label><input type="
password
" id
=
"password" name
=
"password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
|
package stu.action;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
@Component("loginAction")
@Scope("prototype")
public class LoginAction extends ActionSupport {
private static final long serialVersionUID = 1L;
//模拟用户登录
private String userName;
public void setUserName(String userName) {
this.userName = userName;
}
private String password;
public void setPassword(String password) {
this.password = password;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
/*
* 在LoginAction 中添加了validate()方法之后,一旦验证过程中添加了校验信息,那么
* Struts2框架会根据Action的配置跳转到input的视图界面
* */
@Override
public void validate() {
if(this.userName==null||this.userName.trim().length()==0){
this.addFieldError("userName", "用户名不能为空");
}
if(this.userName==null||this.password.trim().length()<6){
this.addFieldError("password", "密码不能小于6位");
}
}
}
|
<?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>
<package name="default" namespace="/" extends="struts-default">
<action name="index" class="studentAction" >
<result name="success">/index.jsp</result>
</action>
<action name="userLogin" class="loginAction">
<result name="success" type="redirect">index</result>
<result name="input">/login.jsp</result>
</action>
</package>
</struts>
|
package stu.action;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
@Component("loginAction")
@Scope("prototype")
public class LoginAction extends ActionSupport {
//省略属性
public void
validateLogin
() {//跳到input视图
if(this.userName==null||this.userName.trim().length()==0){
this
.addFieldError(
"userName"
,
"用户名不能为空"
);
}
if(this.userName==null||this.password.trim().length()<6){
this
.addFieldError(
"password"
,
"密码不能小于6位"
);
}
}
public String
login
() throws Exception {
return SUCCESS;
}
}
|
jsp
<form action="/Stu/userLogin" method="post">
<label for="userName">用户名:</label><input type="text" id="userName" name="userName"/><br/>
<label for="password">密码:</label><input type="text" id="password" name="password"/><br/>
<input type="submit" value="登录"/>
<s:token></s:token><!--一定要有这个标签-->
</form> strutsl.xml
<action name="userLogin" class="loginAction">
<result name="success" type="redirect">index</result>
<result name="input">/login.jsp</result>
<result name="invalid.token">TokenFailed.jsp</result>
<!-- 若重复提交,则会跳转到这个页面,注意这里result的名字,一定要是invalid.token -->
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 这里一定要有这两个拦截器 -->
</action>
|
- 在任何优秀的MVC框架都会提供一些通用的操作,如请求数据的封装,类型转换、数据校验、解析上传文件,防止表单多次提交等。早期的MVC框架将这些操作都写死在核心控制器中,而这些同用的操作并不是所有的请求都需要实现,这会导致框架的灵活性不足,可扩展性降低。
- Struts 2 将它的核心功能放到拦截器中实现而不是集中在核心控制器中实现,八大部分控制器需要完成的工作按功能分开定义,每一个拦截器完成一个功能,而完成这些功能的拦截器可以自由选择、灵活组合,需要哪些拦截器,只需要在struts.xml中指定,从而增强了框架的灵活性。
- 拦截器的方法在Action执行之前之后自动执行,从而将通用的操作动态的插入到Action执行的前后,这样有利于系统的解耦
- 如果有一批拦截器经常固定在一起使用,可以使用拦截器栈,拦截器栈里都是拦截器的引用,从而构成一个更大粒度的拦截器,供其他拦截器使用
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack> |
从com.opensymphony.xwork2.interceptor.Interceptor接口的说明中可以了解到:
1、Interceptor是一个无状态的类,它采用了拦截器模式。采用了javax.servlet.Filter,以及AOP的思想。(这是Interceptor的原理)
2、Interceptor是一个动态的拦截Action调用的对象,使用Interceptor可以在Action调用之前或者之后添加功能,它也可以阻止Action的执行。使用拦截器,可以定义一些通用的功能,然后用于多个Action。(这是Interceptor的功能)
//这是一个打印日志的拦截器
package com.opensymphony.xwork2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LoggingInterceptor extends AbstractInterceptor {
private static final Logger LOG = LogManager.getLogger(LoggingInterceptor.class);
private static final String FINISH_MESSAGE = "Finishing execution stack for action ";
private static final String START_MESSAGE = "Starting execution stack for action ";
@Override
public String intercept(ActionInvocation invocation) throws Exception {
logMessage(invocation, START_MESSAGE);
String result = invocation.invoke();
logMessage(invocation, FINISH_MESSAGE);
return result;
}
private void logMessage(ActionInvocation invocation, String baseMessage) {
if (LOG.isInfoEnabled()) {
StringBuilder message = new StringBuilder(baseMessage);
String namespace = invocation.getProxy().getNamespace();
if ((namespace != null) && (namespace.trim().length() > 0)) {
message.append(namespace).append("/");
}
message.append(invocation.getProxy().getActionName());
LOG.info(message.toString());
}
}
}
|
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);
if (executed) {
throw new IllegalStateException("Action has already executed");
}
if (interceptors.hasNext()) {//通过内部状态判断是否有下一个拦截器
final InterceptorMapping interceptorMapping = interceptors.next();
String interceptorMsg = "interceptorMapping: " + interceptorMapping.getName();
UtilTimerStack.push(interceptorMsg);
try {
Interceptor interceptor = interceptorMapping.getInterceptor();
if (interceptor instanceof WithLazyParams) {
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
}
//invoke()对interceptor的intercept()方法的调用
resultCode = interceptor.intercept(DefaultActionInvocation.this);
} finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
resultCode = invokeActionOnly();
}
// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
if (preResultListeners != null) {
LOG.trace("Executing PreResultListeners for result [{}]", result);
for (Object preResultListener : preResultListeners) {
PreResultListener listener = (PreResultListener) preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
} |
<?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>
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="" class=""></interceptor>
<!--拦截器栈,用于组合多个拦截器-->
<interceptor-stack name="">
<interceptor-ref name=""></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="userLogin" class="loginAction">
<result name="success" type="redirect">index</result>
<result name="input">/login.jsp</result>
<result name="invalid.token">TokenFailed.jsp</result>
<!-- 若重复提交,则会跳转到这个页面,注意这里result的名字,一定要是invalid.token -->
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 这里一定要有这两个拦截器 因为默认拦截器不包含token拦截器-->
</action>
</package>
</
struts
>
|
Struts2的内置拦截器
<interceptor-stack name
=
"defaultStack">
<!--exception拦截器位于所有拦截器的第一个-->
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<!--
servletConfig拦截器提供了一种将源于Servlet API的各种对象注入Action 当中的简洁方法
Action 必须实现相对应的接口,servletConfig 拦截器才能将对应的Servlet 对象注入Action中
-->
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<!--将配置文件中的action元素的子元素param所设置的参数设置到对应的Action属性中-->
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<!--将请求中的数据设置到Action的属性中-->
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<!--当数据校验错误时终止执行流程的功能-->
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
|
自定义拦截器:要么实现要么继承 实现com.opensymphony.xwork2.interceptor.Interceptor接口 继承AbstractInterceptor 类
public abstract class AbstractInterceptor implements Interceptor {
/**
* Does nothing 空实现
*/
public void init() {
}
/**
* Does nothing
空实现
*/
public void destroy() {
}
/**
* Override to handle interception
*/
public abstract String intercept(ActionInvocation invocation) throws Exception;
} 问:为什么在浏览器中直接请求页面,拦截器没有发挥作用? 因为在Struts 2中,拦截器只针对Action的请求才会发生作用,如果直接请求页面,拦截器是不进行响应的 |
Struts 2实现对文件的上传 第一步:添加commons-fileupload-xxx.jar和commons-io-xxx.jar包 第二步:设置 form表单的enctype="multipart/form-data" method="post"
<form action="" enctype="multipart/form-data" method="post">
<s:textfield name="title" label="标题" value=""></s:textfield><br/>
<s:file name="upload" label="选择文件" /><br/>
<s:submit value="上传文件"/>
</form> 第三步:在Action中 写三个私有属性 一个属性的类型是File 名称与jsp页面的 <s:file name="upload" label="选择文件" />name属性相同 另外两个是String类型的 xxxFileName 和String类型的xxxContentType,其中xxx表示文件控件的name属性 |
Struts2常用标签总结
一 介绍
1.Struts2的作用
Struts2标签库提供了主题、模板支持,极大地简化了视图页面的编写,而且,struts2的主题、模板都提供了很好的扩展性。实现了更好的代码复用。Struts2允许在页面中使用自定义组件,这完全能满足项目中页面显示复杂,多变的需求。
Struts2的标签库有一个巨大的改进之处,struts2标签库的标签不依赖于任何表现层技术,也就是说strtus2提供了大部分标签,可以在各种表现技术中使用。包括最常用的jsp页面,也可以说Velocity和FreeMarker等模板技术中的使用
2.Struts2分类
(1)
UI标签:(User Interface, 用户界面)标签,主要用于生成HTML元素标签
,
UI标签又可分为表单标签非、表单标签和Ajax标签
(2)
非UI标签,主要用于数据访问,逻辑控制等的标签
。非UI标签可分为流程控制标签(包括用于实现分支、循环等流程控制的标签)和数据访问标签(主要包括用户输出ValueStack中的值,完成国际化等功能的)
(3)
ajax标签
3.Struts2标签使用前的准备:
(1)在要使用标签的jsp页面引入标签库:
<%@ taglib uri="/struts-tags" prefix="s"%>
(2)在web.xml中声明要使用的标签 这样是struts2 2.3.1.2版本的引入方式
<filter>
<filter-name>struts2</filter-name>
<
filter-
class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
4.标签的使用
(1)
property标签
用于输出ValueStack中对象属性的值,如果没有value 属性则默认输出栈顶的对象,类型为Object,default属性表示属性值为null时的
默认值类型为String
<s:property value="%{@cn.csdn.hr.domain.User@Name}"
default="不能真确显示"
/><
br
/>
<s:property value="@cn.csdn.hr.domain.User@Name"/><Br/><!-- 以上两种方法都可以 -->
<s:property value="%{@cn.csdn.hr.domain.User@study()}"/>
以上可以访问某一个包的类的属性的集中方式,study()是访问方法的方法,并输出。
以下用java代码代替的,访问某一个范围内的属性
<%
//采用pageContext对象往page范围内存入值来 验证#attr搜索顺序是从page开始的 ,搜索的顺序为:page,reques,session,application。
set存值的时候存到的是request中,在jsp页面中访问的时候不用加任何的标识符,即可直接访问,如果不同的作用域不一样了,
pageContext.setAttribute("name", "laoowang", PageContext.PAGE_SCOPE);
%>
<s:property value="#attr.name" />
假设在action中设置了不同作用域的类
不同的作用域的标签的访问:
<h3>获取的是requet中的对象值</h3>
第一种方式:<s:property value="#request.user1.realName"/>
<br/>
第二种方式:<s:property value="#request.user1['realName']"/>
<br/>
第三种方式:<s:property value="#user1.realName"/>
<br/>
第四种方式:<s:property value="#user1['realName']"/>
<br/>
第五种方式:${requestScope.user1.realName } || ${requestScope.user1['realName'] }
第六种:<s:property value="#attr.user1.realName"/>
attr对象按page==> request sessionapplictio找的
<h3>获取session中的值</h3>
第一种方式:<s:property value="#session.user1.realName"/>
<br/>
第二种方式:<s:property value="#session.user1['realName']"/>
第五种方式:${sessionScope.user1.realName } || ${sessionScope.user1['realName'] }
<h3>获取application中的对象的值</h3>
第一种方式:<s:property value="#application.user1.realName"/>
<br/>
第二种方式:<s:property value="#application.user1['realName']"/>
第五种方式:${applicationScope.user1.realName } || ${applicationScope.user1['realName'] }
(2)iterator标签的使用
第一种:list集合
<!-- 设置set集合 value-->
<!-- status 可选属性,该属性指定迭代时的IteratorStatus实例 -->
<!-- value="#attr.list" list存放到了request中 可以value="#request.list"
statu.odd返回当前被迭代元素的索引是否是奇数
-->
<s:set name="list" value="{'a','b','c','d'}"></s:set>
<s:iterator var="ent" value="#request.list" status="statu">
<s:if test="%{#statu.odd}">
<font color="red"><s:property value="#ent" />
</font>
</s:if>
<s:else>
<s:property value="#ent" />
</s:else>
</s:iterator>
第二种:map集合中的使用
<h3>Map集合</h3>
<!-- map集合的特点:
语法格式:# {key:value,key1:value1,key2:value2,.....}
以上的语法中就直接生成了一个Map类型的集合,该Map对象中的每个key-value对象之间用英文的冒号隔开
,多个元素之间用逗号分隔。
-->
</div>
<s:set var="map" value="#{'1':'laowang','2':'老王','3':'猩猩'}"></s:set>
遍历Map:
<br />
<s:iterator value="#map">
<s:property value="key" />:::<s:property value="value" />
<Br />
</s:iterator>\
第三种:集合的变量
<h3>遍历集合:::</h3>
<div>
<!-- 遍历出价格大于3000的 -->
<s:iterator var="user" value="#session['users']">
<s:if test="%{#user['price']>3000}">
<s:property value="#user['price']"/>
</s:if>
</s:iterator>
<hr color="blue"/><!-- $是取出价格 大于3000的最后一个值 -->
<s:iterator var="u" value="#session.users.{$(#this['price']>3000)}">
<s:property value="price"/>
</s:iterator>
</div>
注:users是User的对象,price是User中的一个属性
简述一下iterator的介绍:
iterator标签用于对集合进行迭代,这里的集合包含List、Set和数组。
<s:set name="list" value="{'zhangming','xiaoi','liming'}" />
<s:iterator value="#list" status="st">
<font color=<s:if test="#st.odd">red</s:if><s:else>blue</s:else>>
<s:property /></font><br>
</s:iterator>
value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。
id:可选属性,指定集合里元素的id。
status:可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下几个方法:
int getCount(),返回当前迭代了几个元素。
int getIndex(),返回当前迭代元素的索引。
boolean isEven(),返回当前被迭代元素的索引是否是偶数
boolean isOdd(),返回当前被迭代元素的索引是否是奇数
boolean isFirst(),返回当前被迭代元素是否是第一个元素。
boolean isLast(),返回当前被迭代元素是否是最后一个元素。
(3)if else语句的使用
<s:set name="age" value="21" />
<s:if test="#age==23">
23
</s:if>
<s:elseif test="#age==21">
21
</s:elseif>
<s:else>
都不等
</s:else>
(4)URL标签
<!-- 声明一个URL地址 -->
<s:url action="test" namespace="/tag" var="add">
<s:param name="username">laowangang</s:param>
<s:param name="id">12</s:param>
</s:url>
<s:a href="%{add}">测试URL</s:a>
<s:a action="test" namespace="/tag"></s:a>
以上的两个<s:a>标签的作用是一样的。
(5)data标签
<%
pageContext.setAttribute("birth",new Date(200,03,10),PageContext.REQUEST_SCOPE);
%>
<s:date name="#request.birth" format="yyyy年MM月dd日"/>
<s:date name="#request.birth" nice="true"/>
这个标签是按照format的格式去输出的。
(6)表单
<h1>from表单</h1>
<s:form action="test" namespace="/tag">
<s:textfield label="用户名" name="uname" tooltip="你的名字" javascriptTooltip="false"></s:textfield>
<s:textarea name="rmake" cols="40" rows="20" tooltipDelay="300" tooltip="hi" label="备注" javascriptTooltip="true"></s:textarea>
<s:password label="密码" name="upass"></s:password>
<s:file name="file" label="上传文件"></s:file>
<s:hidden name="id" value="1"></s:hidden>
<!--
<select name="edu">
<option value="listKey">listValue</option>
-->
<s:select list="#{'1':'博士','2':'硕士'}" name="edu" label="学历" listKey="key" listValue="value"></s:select>
<s:select list="{'java','.net'}" value="java"></s:select><!-- value是选中的 -->
<!-- 必须有name -->
<s:checkbox label="爱好 " fieldValue="true" name="checkboxFiled1"></s:checkbox>
<!-- 多个checkbox -->
<s:checkboxlist list="{'java','css','html','struts2'}" label="喜欢的编程语言" name="box" value="{'css','struts2'}"></s:checkboxlist>
<!-- map集合前要加# -->
<s:checkboxlist list="#{1:'java',2:'css',3:'html',4:'struts2',5:'spring'}" label="喜欢的编程语言" name="boxs" value="{1,2}"></s:checkboxlist>
<!-- listKey
listValue
<input type="text" name="boxs" value="listKey">显示值listValue
-->
<!-- radio -->
<%
//从服务器传过来值
pageContext.setAttribute("sex","男",PageContext.REQUEST_SCOPE);
pageContext.setAttribute("sex1","男",PageContext.REQUEST_SCOPE);
%>
<s:radio list="{'男','女'}" name="sex" value="#request.sex"></s:radio>
<s:radio list="#{1:'男',2:'女'}" name="sex1" listKey="key" listValue="value" value="#request.sex1"></s:radio>
<!-- 防止表单提交的方式 -->
<s:token></s:token>
<s:submit value="提交"></s:submit>
</s:form> |