1.上一篇文章,我介绍了OGNL表达式语言,本来想在那篇文章上加上一个使用OGNL访问静态方法和静态属性的例子,但是昨天晚上我写代码时,报了一个警告,获取得到静态属性的值,却获取不到静态方法的返回值,所以今天特别的写篇文章来介绍一下。
2.这里我先附上这个例子,来了解如何使用OGNL表达式访问静态方法和属性。
(1).其中访问静态方法或者静态属性的语法分别为:@类的路径@方法名,@类的路径@属性名,语法中类的路径,即包名+类名。
(2).对于OGNL来说,java.lang.Math是其默认的类,如果调用java.lang.Math的静态方法时,无需指定类的名字,比如:@@min(4,10),就比较两者谁比较小,输出较小的那个数。
注:其中第一点也可以理解为调用一个类的静态方法和静态属性,其中第二点也可以理解为调用JDK类中的静态方法。
(3).项目结构图如下:
(4).首先新建一个Struts2项目,项目名为StaticTest,新建一个类,放在com.gk包下,类名为StaticTest,完整代码如下:
package com.gk;
public class StaticTest{
public static String str="static property";
public static String s(){
return "static method";
}
}
打开index.jsp页面,编码格式改为utf-8,加入<%@ taglib uri="/struts-tags" prefix="s" %>,就可以使用struts的标签,具体代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
My JSP 'index.jsp' starting page
- 访问静态方法:
- 访问静态属性:
- 访问java.lang.Math类的静态方法:
一定要在struts.xml配置文件中配置允许使用OGNL访问静态方法,否则不能使用OGNL访问静态方法,必须在struts.xml文件中加入这行代码:
其中完整struts.xml文件如下:
(5).接着部署该项目到Tomcat服务器上,开启Tomcat服务器,运行后如下:
为何取不到静态方法的返回值呢?很奇怪!
3.发现访问静态方法,获取不出它的返回值,然后看一下控制台,有警告信息,但是不是错误,警告信息如下图所示:
这个警告信息使我搞了我半天都没解决,控制台输出的信息是com.opensymphony.xwork2.ognl.SecurityMemberAccess warn个类警告,警告内容是Target class [class com.gk.StaticTest] or declaring class of member type [public static java.lang.String com.gk.StaticTest.s()] are excluded! ,意思是目标类StaicTest类或者声明类的成员类型[public static java.lang.String com.gk.StaticTest.s()]是被排除,被赶出了,表明意思是这样,我就百度了一下,发现有小部分的同学都会报这错误,但是都没解决,所以我就去查看一下底层代码,看能看出个所以然么?
(1).这个警告是com.opensymphony.xwork2.ognl.SecurityMemberAccess warn,所以我就找到这个SecurityMemberAccess类,它是放在com.opensymphony.xwork2.ognl包下的,而这个包是放在xwork-core-2.3.20.jar 包下的,所以我们必须导入这个包的源代码,才能查看,这个导入我在之前的文章说过,这里再用图的方式显示一次:
首先找到这个jar包:
选中这个jar包,然后鼠标右键单击,选择Properties属性,找到你下载的那个搭建环境所需要的包,然后找到xwork-core相关的文件,即E:/struts-2.3.20/struts-2.3.20/src/xwork-core/src/main/java,复制到下图的红色框框的地方,点击箭头指向的两个按钮,首先Apply应用按钮,再点击Ok确定按钮:
这样我们就可以打开这个jar包下的.class文件,都是我们熟悉的Java代码。
(2).打开com.opensymphony.xwork2.ognl包下的SecurityMemberAccess类,即如下图所示:
双击打开后,代码如下:
/*
* Copyright 2002-2006,2009 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import ognl.DefaultMemberAccess;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Allows access decisions to be made on the basis of whether a member is static or not.
* Also blocks or allows access to properties.
*/
public class SecurityMemberAccess extends DefaultMemberAccess {
private static final Logger LOG = LoggerFactory.getLogger(SecurityMemberAccess.class);
private final boolean allowStaticMethodAccess;
private Set excludeProperties = Collections.emptySet();
private Set acceptProperties = Collections.emptySet();
private Set> excludedClasses = Collections.emptySet();
private Set excludedPackageNamePatterns = Collections.emptySet();
public SecurityMemberAccess(boolean method) {
super(false);
allowStaticMethodAccess = method;
}
public boolean getAllowStaticMethodAccess() {
return allowStaticMethodAccess;
}
@Override
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
if (checkEnumAccess(target, member)) {
if (LOG.isTraceEnabled()) {
LOG.trace("Allowing access to enum #0", target);
}
return true;
}
if (isPackageExcluded(target.getClass().getPackage(), member.getDeclaringClass().getPackage())) {
if (LOG.isWarnEnabled()) {
LOG.warn("Package of target [#0] or package of member [#1] are excluded!", target, member);
}
return false;
}
if (isClassExcluded(target.getClass(), member.getDeclaringClass())) {
if (LOG.isWarnEnabled()) {
LOG.warn("Target class [#0] or declaring class of member type [#1] are excluded!", target, member);
}
return false;
}
boolean allow = true;
if (!checkStaticMethodAccess(member)) {
if (LOG.isTraceEnabled()) {
LOG.warn("Access to static [#0] is blocked!", member);
}
allow = false;
}
//failed static test
if (!allow)
return false;
// Now check for standard scope rules
return super.isAccessible(context, target, member, propertyName)
&& isAcceptableProperty(propertyName);
}
protected boolean checkStaticMethodAccess(Member member) {
int modifiers = member.getModifiers();
if (Modifier.isStatic(modifiers)) {
return allowStaticMethodAccess;
} else {
return true;
}
}
protected boolean checkEnumAccess(Object target, Member member) {
if (target instanceof Class) {
Class clazz = (Class) target;
if (Enum.class.isAssignableFrom(clazz) && member.getName().equals("values"))
return true;
}
return false;
}
protected boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
for (Pattern pattern : excludedPackageNamePatterns) {
if (pattern.matcher(targetPackage.getName()).matches() || pattern.matcher(memberPackage.getName()).matches()) {
return true;
}
}
return false;
}
protected boolean isClassExcluded(Class> targetClass, Class> declaringClass) {
if (targetClass == Object.class || declaringClass == Object.class) {
return true;
}
for (Class> excludedClass : excludedClasses) {
if (targetClass.isAssignableFrom(excludedClass) || declaringClass.isAssignableFrom(excludedClass)) {
return true;
}
}
return false;
}
protected boolean isAcceptableProperty(String name) {
return name == null || ((!isExcluded(name)) && isAccepted(name));
}
protected boolean isAccepted(String paramName) {
if (!this.acceptProperties.isEmpty()) {
for (Pattern pattern : acceptProperties) {
Matcher matcher = pattern.matcher(paramName);
if (matcher.matches()) {
return true;
}
}
//no match, but acceptedParams is not empty
return false;
}
//empty acceptedParams
return true;
}
protected boolean isExcluded(String paramName) {
if (!this.excludeProperties.isEmpty()) {
for (Pattern pattern : excludeProperties) {
Matcher matcher = pattern.matcher(paramName);
if (matcher.matches()) {
return true;
}
}
}
return false;
}
public void setExcludeProperties(Set excludeProperties) {
this.excludeProperties = excludeProperties;
}
public void setAcceptProperties(Set acceptedProperties) {
this.acceptProperties = acceptedProperties;
}
public void setExcludedClasses(Set> excludedClasses) {
this.excludedClasses = excludedClasses;
}
public void setExcludedPackageNamePatterns(Set excludedPackageNamePatterns) {
this.excludedPackageNamePatterns = excludedPackageNamePatterns;
}
}
代码也不多,我们只看重要的,可以通过大纲看代码:
大纲中有变量,常量,和方法,一个个点击来看,其中我找到了报错的那一行,但是看了也不知道怎么解决,郁闷!如下图所示:
它就是报这行警告,这行警告是通过判断isClassExcluded这个方法来决定的:
这个方法判断了目标类和超类是否相等或者声明类和超类是否相同,相等的话返回真,这就不多做解释了,然后我们报错的那行的那幅图里传进来的两个类,一个是目标类,一个是声明类,而这个声明类是通过成员来获得的,这又不知道为何了,所以看底层代码又看不懂,所以只能求助我热心的群友了。
注:这里我为何要介绍看底层代码呢,因为这样有利于我们理解和学习代码为什么这样写,又为什么报这警告。由于水平有限,所以我也郁闷了!
(3).我就去请教一下我的群友,我那个群是安卓群,发了一下牢骚,群友就问你遇到什么问题了,说一下,看我懂不,我就跟他们说了这个问题,过了一会儿一位群友说我去Struts的官网查了下,说最新版本的struts2不支持OGNL访问静态方法了,估计是因为安全问题,访问静态方法怕不安全,想想我用的还真是最新版本,我说难怪老师要我们用较稳定的版本,别用最新的,果然,我把上面这个项目的核心代码复制到低版本的项目中,就可以了,真是一波三折啊!
4.以上那个例子的代码是没错的,是因为版本问题,才导致只可以使用OGNL访问静态属性,而访问不了静态方法,所以我使用较低版本jar包,我把上面这个项目的一些代码复制,调整一下,改变一些名字等等,我用的是下图的版本:
一切搞定之后,运行效果如下:
这样就可以使用OGNL访问静态方法,并获取得到它的值。
5.总结:对于使用OGNL表达式语言来访问静态方法,这个比较少用,如果在使用OGNL访问静态方法,但是获取不到值,并控制台输出如上面我所介绍的一些警告信息,有可能是你版本是最新的原因,代码是没错误的,所以建议大家使用较稳定版本,使用较稳定版本后,通过上面这个例子就可以使用OGNL访问静态方法并获取其静态方法的返回值。
6.以上内容仅供大家学习参考,写的不好,请见谅,如有问题,请指出,如文章有错误,请指出,谢谢!