5).OGNL表达式-操作数据空间
O(Object) G(Graphic) N(Navigation) L(Language) 对象 图 导航语言
作用:通过表达式方式(非Java代码)的方式操作指定数据。
特点:(对比EL)
①可以调用方法
②可以存入数据(绑定数据)
OGNL可以操作数据空间(对象):
导入jar: ognl.jar
① ognl向root区的对象中存入数据
Ognl.setValue("root区的对象的属性名",root区对象,值);
②ognl从root区的对象中获取数据
Object ognl表达式获取的结果 = Ognl.getValue("root区对象的属性名",root区对象);
③调用方法
语法: Ognl: "对象.方法名(参数)"
注意: 表示字符串 "zxxx" '1000'(如果ognl外部使用双引号,内部字符串使用单引号)
④数学运算和逻辑运算
+ - * / % == != ! && ||
注意: (1==“1”)忽略数据类型;(10/3结果为3) 数字除运算, 按照java运算规则计算
⑤Ognl访问List集合类型数据
语法: ognl: "list集合[i]"
⑥Ognl访问Map集合元素
语法: ognl:
"map对象.key" key不能是纯数字内容。
"map对象['key']" key可以数字或者字符串。
⑦Ognl从context区域获取数据
重点: context区域是一个map结构
key是字符串、value对象类型
语法: Ognl表达式: "#key" context中map的value
测试方法: Ognl.getValue("ognl表达式",放入context区的map,root对象);
6).OGNL表达式-值栈(ValueStack)、Struts2值栈的使用+Struts2标签库[重点]
(1)值栈 ValueStack(类名)
作用:
封装ognl的root和context
使用Ognl表达式访问值栈内部root区中的对象,context中map的key对应的value
值栈相关api:
①获得值栈对象
ValueStack vs = ActionContext.getContext().getValueStack();
②获得root(栈)
CompoundRoot root = vs.getRoot();
③向root中存入对象
root.push(作为root对象);
④获得context
Map<String,Object> context = vs.getContext();
⑤如果想context中存入数据
context.put("key",值);
⑥值栈对象提供方法 vs.findValue("ognl表达式"), 使用ognl获得值栈中的数据。
获取root区属性值: vs.findValue(“对象属性”);
获取ContextMap区value: vs.findValue(“#key”);
(2)Struts2值栈的使用+Struts2标签库[重点]
Struts2对值栈的管理
①值栈:
Context区(数据结构 Map)[重点]
"request" RequestMap(相当于HttpServletRequest作用域)
"session" SessionMap(相当于HttpSession作用域)
"application" ApplicationMap(相当于ServletContext作用域)
Root区(数据结构 栈 Stack)
将当前的Action对象放在root区栈顶。
②struts2标签库:
使用:
a.引入标签库:<%@taglib uri="/struts-tags" prefix="s" %>
b.使用property标签:<s:property value="ognl表达式"></s:property>
作用:
a.执行ognl获得数据
b.将结果展示给浏览器
③总结:
a. 向RequestMap中存入值
Map<String,Object> requestMap = (...)vs.getContext().get("request");
requestMap.put("名字key",值);
通过Ognl表达式访问RequestMap(相当于request作用域)
OGNL: "#request.requestmap中的key"
b. 向SessionMap存入值
Map<String,Object> sessionMap = (..)vs.getContext().get("session");
sessionMap.put("key",value)
通过Ognl表达式访问SessionMap(相当于session作用域)
OGNL: "#session.sessionMap中的key"
c. 通过Ognl表达式访问当前的Action的属性值:
注意: Action生命周期是一次请求过程。(请求转发)
OGNL: "Action的属性名"
7).OGNL表达式-常用的Struts2标签、及在struts.xml中使用
(1)常用Struts2标签(在JSP中使用OGNL)
①property
语法: <s:property value="OGNL表达式,值栈的root获取值,context获得值"/>
作用:
a.执行ognl表达式,获得数据
b.讲结果显示给浏览器。
常用:
<s:property value="Action的属性名"/> [获得action的属性值]
<s:property value="#request.requestMap的key"/> [获得相当于request作用域的requestMap的值]
<s:property value="#session.sessionmap的key"/> [获得相当于session作用域的sessionMap的值]
补充:
<s:property/> [获得的值栈的root区栈顶的对象]
②格式化日期
<s:date name="ognl获得要格式化显示的日期" format="设置日期格式"/>
日期格式:
年yyyy 月MM 日dd
③判断
语法: <s:if test="OGNL获得数据并逻辑判断1">条件1成立</s:if>
<s:elseif test="ognl条件2">条件2成立</s:elseif>
<s:else>都不成立</s:else>
④遍历ListJ集合
<s:iterator value="OGNL被遍历的集合">
<s:property/>当前被遍历的对象:被遍历的当前对象被放在了root区的栈顶位置
<s:property value="当前对象的属性名"/>当前被遍历的对象的属性
</s:iterator>
作用: a. value属性遍历集合;b. 遍历过程中,每个被遍历的当前对象,暂时放在值栈的root区的栈顶。
属性介绍:
value: OGNL获得被遍历集合
begin: 起始下标
end: 截止下标
step: 步长 [配合 begin="0"]
status="vs" (vs.index(下标序号); vs.count(排序序号))
注意: 将vs存入值栈的context中。key="vs"
⑤遍历Map
<s:interator value="ognl获得map">
将遍历的每个当前对象(Map.Entry key+value),放入root栈顶。
展示key: <s:property value="key"/>
获得value: <s:property value="value"/>
</s:interator>
⑥url重写
<s:url value="请求资源的路径"></s:url>
作用:
a. 自动补全 "/项目名"
b. cookie被禁用的请情况下对url进行重写。(url;jsessionid=1234asdd1234asd);
⑦action请求标签
语法: s:action name="" namespace="" executeResult="true"></s:action>
作用:向action发起请求,接收服务器响应的结果。
属性:
name: 请求的action的name
namespace: 请求的action的命名空间namespace
executeResult: 是否包含action的执行结果页面。
(2)Struts2标签在struts.xml中使用
struts.xml书写OGNL表达式
ognl在struts.xml获得root中当前Action的属性名,作用域对应的map中的值。
语法: ${ognl表达式}
在跳转路径中使用超链接传值:
8).OGNL表达式-值栈的生命周期、及其原理(如何替代作用域)
(1)值栈的生命周期
生命周期: 一次请求过程.
(2)#值栈如何替代作用域的(原理)
原理:值栈的生命周期一次请求过程,但是值栈的context中的sessionMap中的数据可以跨请求存在,是因为其
最终保存在HttpSession作用域中,HttpSession可跨多次请求。
SessionMap底层源码实现:
存入: 讲put方法接受的key和value,session.setAttribute(key,value);保存在session作用域中,。
取出: 讲get方法接受key,session.getAttribute(key);,从session作用域中获的值
9).拦截器(Interceptor)、拦截器栈(组)
(1)拦截器
概念: 拦截浏览器请求struts2的Action.
作用(应用): 提取多个Action中的共同代码(通用功能),到拦截器中完成。
运行机制:
①请求访问Action,会先经过拦截器中代码。
②请求经过拦截调用方法: intercept(ActionInvocation ai)
ai.invoke();//放行action的请求。
拦截器核心工作机制:(类比Filter)
编码实现拦截器:
①自定义一个类,实现Interceptor接口
public class MyInterceptor implements Interceptor{
//请求到达拦截器的执行方法。(类似filter中doFilter)
intercept(ai){
Action之前运行的代码
ai.invoke();//放行请求。
Action运行之后的代码
}
}
②注册配置拦截器(拦截器被struts2管理)
<interceptors>
<intercept name="名字" class=""></intercept>
</interceptors>
③在需要拦截的action中引用拦截器(名字)
④拦截器修改跳转路径:
⑤拦截器和Action+跳转的完整流程。
(2)拦截器栈(组)
拦截器注意事项:
如果aciton引用自定义拦截器的话,默认拦截器就失效了。
struts-default[笔试]
struts.xml中, `extends="struts-default"`
默认拦截器中配置大量struts核心拦截器,(请求参数自动接收,文件上传,值栈,编码设置),如果action要使用这些拦截器,必须继承struts-default配置文件的额信息。而且还要引入Struts默认的拦截器,放到自己定义的拦截器栈的首个位置:
10).Struts应用-文件的上传、下载
(1)文件上传
步骤:
①浏览器页面(文件选择输入框
a. 文件输入框
b. 表单提交方式 post
c. 设置表单以二进制流提交: form enctyp="multipart/form-data"
②Action接受文件
public class FileAction{
private File 文件输入框的name;
//set get;
}
③在action讲接受file对象拷贝保存在tomcat项目所在的目录下
//动态获得服务器中项目下的文件夹路径
ServletContext ctx = ServletActionContext.getServletContext();
String realPath = ctx.getRealPath("/upload");//upload文件夹的真实路径
String fileName = "hehe.jpg";
String filePath = realPath+"/"+fileName;
//headPic文件----->filePath路径
OutputStream os = new FileOutputStream(filePath);
BufferedOutputStream bos = new BufferedOutputStream(os);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(headPic));
byte[] bs = new byte[1024];
while(true){
int i = bis.read(bs);//读入bs数组多少长度
if(i<0)break;
bos.write(bs, 0, i);
}
bos.flush();
bos.close();
bis.close();
④获得上传文件名:
文件上传优化
①文件大小
默认struts接受上传文件大小上限: 2M;
<!-- 常量配置设置文件上传的大小 -->
<!-- struts.multipart.maxSize=2097152 100M 1字节*100000000 -->
<constant name="struts.multipart.maxSize" value="100000000"></constant>
②文件名
问题: 文件名在服务器端冲突。
解决: 使用UUID生成唯一的名字作为文件名。
代码: UUID.randomUUID().toString();"1234-1234-asdfg-2345-435"
文件名设计: UUID+".后缀";
③保存路径
问题: 保存文件的目录写死在代码中,耦合,不便于维护。
解决办法: 保存目录名转移到配置文件。
④ io工具类:commons-io的jar包
文件拷贝代码简化:FileUtils.copyFile();
(2)文件下载
使浏览器保存该文件,而不是解析展示该文件?
给浏览器设置头信息: "content-disposition" "attachment;filename=文件.后缀"
①设置下载;
response.setHeader("content-disposition", "attachment;filename="+fileName);
②读入服务器端文件输入流
③指向浏览器的输入流
④边读边写
补充:
对下载的文件名编码:
URLEncoder.encode(字符串,"UTF-8");
11).Struts应用-验证码、令牌、日期转化(String/util.Date/sql.Date)
(1)验证码
作用:
①防止机器人登陆,对系统添加无效信息
②防止机器人,恶意注册无效用户信息
使用java生成验证码图片:
①产生一个随机验证码字符串
②如何将字符串生成图片中
public static BufferedImage getSafeCodeImage(String code) throws IOException {
BufferedImage bi = new BufferedImage(80, 30, BufferedImage.TYPE_INT_BGR);
Graphics g = bi.getGraphics();
g.fillRect(0, 0, 80, 30);
g.setColor(Color.BLUE);
g.drawString(code, 20, 12);
/*ImageIO.write(bi, "jpg", new FileOutputStream("D:\a.jpg"));*/
return bi;
}
public static String getGenerateCode(int n) {
String str = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
Random rd = new Random();
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < n; i++) {
sb.append(str.charAt(rd.nextInt(62)));
}
return sb.toString();
}
在jsp中产生一个验证码:
验证码工具类:
Hutool(工具包)
导入hutool的jar包。
CaptchaUtil 功能: 生成随机验证码(字符串)、 生成验证码图片,直接通过流写出
代码步骤:
①生成验证码对象:
Captcha captcha = CaptchaUtil.createLineCaptcha(宽度,高度,字符个数,干扰线个数);
Captcha captcha = CaptchaUtil.createLineCaptcha(宽度,高度);
②生成验证码:
captcha.getCode();//code字符串
captcha.write(outputStream);//将验证码图片通过输出流,写出到对应位置
jsp使用验证码核心思路:依靠image的src,请求生成验证码图片的action,响应写回去
使用:
(2)Struts2令牌机制
防止表单重复提交
①分发令牌
Struts中给用户分发令牌方式: <s:token></s:token>
作用:
a. 给用户的浏览器的表单放入一个随机字符串。
b. 将字符串(令牌),向session中存入一份。
核心机制:
②验证令牌
验证令牌核心机制
编码步骤:
a. 书写一个验证令牌的拦截器(struts已经提供了)
b. 配置令牌拦截器拦截防止重复提交的action
c. Action必须继承ActionSupport.
(3)日期格式
①java.util.Date和java.sql.Date之间的转换:
中间值:Date.getTime();
例:
long l = (new java.util.Date()).getTime();
java.sql.Date d = new java.sql.Date(l);
②String格式转换为日期格式
日期格式化工具: SimpleDateFormat
String s = "1999-9-9";
//1. 创建日期格式化工具,(匹配日期格式)
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//2. 调用转发方法
Date parse = format.parse(s);