- 浏览: 42996 次
- 性别:
- 来自: 上海
最新评论
-
ta8210:
还是我的老话。
如果将配置文件中的内容,移动到类中做注解。
...
打造0配置文件的SSH框架-10 -
ta8210:
配置文件零化了,但是这不叫零配置。
将配置文件中的内容,移动 ...
打造0配置文件的SSH框架-10 -
tvjody:
spring 中提供相关的包加载配置文件
<bean ...
打造0配置文件的SSH框架-3 -
TaoistWar:
要是SSH,一个人扔给他一个applicationContex ...
打造0配置文件的SSH框架-3 -
TaoistWar:
我还以为是用注解呢!
打造0配置文件的SSH框架-3
MethodActionConfigurationProvider完整源码
两个用zero config配置的action的例子,一个简单的,一个复杂
看起来还是比较清晰的
加载有@标记的类:现在实现的是在WEB.XML文件中写出包含有@标记的Action所在的包。但是我觉得在WEB.XML中去写不是很方便,因为在项目中并不是每个人都有权利去修改这个文件。所以我觉得在复写XmlConfigurationProvider的时候最好去struts.xml类中去加载包名。根据包名加载都做好了,那还可以添加一个根据类名加载吧呵呵 ,不是很有必要随便说说。
其实就是因为不是每个人都有权利去修改这个web.xml文件,所以才会想出来配置一个目录,然后系统自动去搜索目录下的包括子目录的所有action类。
项目中只要定好,所有的action类必须在某一个目录下,比如sample.web.action这样的目录,具体各个模块再在这个目录的基础上分子目录,web.xml只要定义该目录sample.web.action就可以了。
也像你说的那样,要扩展struts dtd比较麻烦,我要改struts包中的dtd或者改配置文件上的dtd验证url,这样导致struts的xml不标准,对struts的入侵太厉害,毕竟这样就是修改而不是扩展struts的代码了。
如果用了@Annotation的话就不能用XML了,所以我建议你不要继承接口而是继承XmlConfigurationProvider类,让同时可以加载xml的配置和@的配置。不同package共用的result Exception还是在struts.xml中配置比较合适。这样的话struts.xml文件还是有存在的必要
这条好像不太对,我们现在就是@annotation和xml一起用,而且正如你想的不同package共用的result Exception, global result, interceptor等等信息都是在struts.xml文件中配置的。
其实struts加载的时候,是先加载XmlConfigurationProvider,再加载自定义的Provider,所以肯定是先加载xml,在加载annotation。
难道你的xml和annotation不能一起用?
标记@Action的Target类型是METHOD的,为什么不可以写在TYPE和METHOD呢?甚至一个类中的共用的Result,EXCEPTION,INTERCEPOTR也可以写在类上边啊……因为一个Action类中的CRUD方法返回的结果集和处理错误集很有可能返回的结果是一样的。处理异常也可能一样等等。而对于不同的业务处理方法也可能有特殊的返回结果。这样在这个方法前边只标记他特殊的Result Exception什么什么的
这个....我发的东西的版本比我们项目在用的版本早,后来的版本中,result, exception, interceptor都可以定义在class这个级别上,甚至定义在package-info.java中,这样甚至可以一个package下所有的action class共用一些信息,代码没有贴出来
/** * 集成xwork的config provier,用来加载brick针对struts2的zero config配置 * @author leeon */ public class MethodActionConfigurationProvider implements ConfigurationProvider { private static final Log logger = LogFactory.getLog(MethodActionConfigurationProvider.class); /** * 用来获取xwork config对象,通过该对象来加载config */ private Configuration configuration = null; /** * 从外部传入的参数,用来记录哪些package有zero config的配置类,程序好搜索这些pkg */ private String methodActionPackage = null; /** * 用于记录哪些文件被读取过,根据是否修改来判断是否进行reload操作 */ private Map<String, Long> loadedClassUrls = new HashMap<String, Long>(); /** * xwork的object factory,用来管理result, iterceptor等配置 */ private ObjectFactory objectFactory = null; private final static String DEFAULT_METHOD_ACTION_PACKAGE = "brick.web.extend.struts.methodActionPackage"; /** * 构造方法 * @param methodActionPackage */ public MethodActionConfigurationProvider() { } /** * 解构方法,清除loaded url */ public void destroy() { loadedClassUrls.clear(); } /** * 继承接口的初始化方法,可以获取到config实例 */ public void init(Configuration configuration) throws ConfigurationException { this.configuration = configuration; this.loadedClassUrls.clear(); } /** * 通过xwork inject获取object factory的方法 * @param objectFactory */ @Inject public void setObjectFactory(ObjectFactory objectFactory) { this.objectFactory = objectFactory; } /** * 通过xwork inject获取methodActionPackage的方法 * @param context */ @Inject(value=DEFAULT_METHOD_ACTION_PACKAGE) public void setMethodActionPackage(String methodActionPackage) { this.methodActionPackage = methodActionPackage.replace('.', '/'); } /** * 继承接口的load pak的方法 */ public void loadPackages() throws ConfigurationException { //读取需要寻找Action类的目录 String[] l = this.methodActionPackage.split(","); //搜索所有package类 List<String> c = new ArrayList<String>(); for (String p:l) { try { c.addAll(FileUtil.searchFileFromClassPath(p, ".*\\.class")); } catch (Exception e) { logger.warn("search file from method action package error:["+p+"]", e); } } //读取package信息 for (String clsName:c) { String className = clsName.substring(0, clsName.length() - 6); className = className.replace('/', '.'); Class<?> clazz = null; try { clazz = Class.forName(className); } catch (ClassNotFoundException e) { logger.warn("class load method action error:["+className+"]", e); continue; } Package p = (Package)clazz.getAnnotation(Package.class); if (p == null) continue; //读取package PackageConfig pc = createPackageConfig(clazz, p); //将该类的路径加入Loadedfile try { loadedClassUrls.put(clsName, BeanUtil.getClassPathFile(clsName).lastModified()); } catch (Exception e) { logger.warn("get class file last modify date from filesystem error :["+clsName+"]", e); } logger.trace("find action package and loaded:["+pc.getName()+","+pc.getNamespace()+"]"); //读取action信息 Method[] m = clazz.getMethods(); for(Method method:m) { Action action = (Action)method.getAnnotation(Action.class); if (action == null) continue; logger.trace("find action method and start parsing:["+action.name()+","+method.getName()+"]"); //读取action的参数 Map<String, Object> ps = this.createParameters(action.param()); //读取action的exception mapping信息 List<ExceptionMappingConfig> le = this.createExceptionMappingConfigs( (ActionExceptionMappings)method.getAnnotation(ActionExceptionMappings.class)); //读取单个的e m信息 ExceptionMappingConfig em = this.createExceptionMappingConfig((ActionExceptionMapping)method.getAnnotation(ActionExceptionMapping.class)); if (em != null) le.add(em); //读取action的interceptor信息 List<InterceptorMapping> li = this.createInterceptorMappings( (ActionInterceptors)method.getAnnotation(ActionInterceptors.class), pc); //读取单个的i信息 li.addAll(this.createInterceptorMapping( (ActionInterceptor)method.getAnnotation(ActionInterceptor.class), pc)); //读取action的result信息 Map<String, ResultConfig> msr = this.createResultConfigs( (ActionResults)method.getAnnotation(ActionResults.class), pc); //读取单个的action r信息 ResultConfig rc = this.createResultConfig((ActionResult)method.getAnnotation(ActionResult.class), pc); if (rc != null) msr.put(rc.getName(), rc); //构建Action config,并添加到package config中 ActionConfig ac = new ActionConfig(method.getName(), clazz, ps, msr, li, le); pc.addActionConfig(action.name(), ac); logger.trace("find action method and end parsing:["+action.name()+","+method.getName()+"]"); } //加载到configuration中 this.configuration.addPackageConfig(pc.getName(), pc); } } /** * 是否允许热加载 */ public boolean needsReload() { Set<String> s = loadedClassUrls.keySet(); for (String clz : s) { //获取类的上次修改时间 long now = 0; try { now = BeanUtil.getClassPathFile(clz).lastModified(); } catch (Exception e) { logger.warn("get class file last modify date from filesystem error :["+clz+"]", e); } //根据修改时间和已经记录的修改时间对比,如果发生修改那么reload if (loadedClassUrls.get(clz).longValue() != now) { logger.trace("find action package class modified and will reload:["+clz+"]"); return true; } } return false; } /** * 必须实现但没有作用的方法 */ public void register(ContainerBuilder arg0, LocatableProperties arg1) throws ConfigurationException { } /** * 根据参数创建package * @param clazz * @param p * @return */ private PackageConfig createPackageConfig(Class clazz, Package p) { //根据类名创建package PackageConfig pc = new PackageConfig(clazz.getName()); //获取名字空间 pc.setNamespace(p.namespace()); //搜索parent,如果没有找到抛出警告 PackageConfig parent = this.configuration.getPackageConfig(p.parent()); if (parent != null) pc.addParent(parent); else ; //返回 return pc; } /** * 装载exception mapping config * 默认使用name和result同名 * @param ems * @return */ private List<ExceptionMappingConfig> createExceptionMappingConfigs(ActionExceptionMappings ems) { //构造返回的List List<ExceptionMappingConfig> list = new ArrayList<ExceptionMappingConfig>(); if (ems == null) return list; //读取aem信息 ActionExceptionMapping aems[] = ems.value(); for (ActionExceptionMapping aem : aems) { ExceptionMappingConfig emc = new ExceptionMappingConfig( aem.result(), aem.exceptionClass().getName(), aem.result(), createParameters(aem.param())); if (emc != null) list.add(emc); } //返回结果list return list; } /** * 用于构造单个的action exception mapping * @param em * @return */ private ExceptionMappingConfig createExceptionMappingConfig(ActionExceptionMapping em) { if (em == null) return null; ExceptionMappingConfig emc = new ExceptionMappingConfig( em.result(), em.exceptionClass().getName(), em.result(), createParameters(em.param())); return emc; } /** * 装载interceptor 集合 * @param is * @param pc * @return */ private List<InterceptorMapping> createInterceptorMappings(ActionInterceptors is, PackageConfig pc) { //构造返回的i集合列表 List<InterceptorMapping> list = new ArrayList<InterceptorMapping>(); if (is == null) return list; //调用单个的构造方法进行构造 ActionInterceptor ais[] = is.value(); for (ActionInterceptor ai : ais) { list.addAll(createInterceptorMapping(ai, pc)); } //返回结果 return list; } /** * 装载单个的interceptor * @param interceptor * @param pc * @return */ private List<InterceptorMapping> createInterceptorMapping(ActionInterceptor interceptor, PackageConfig pc) { List<InterceptorMapping> list = new ArrayList<InterceptorMapping>(); if (interceptor == null) return list; //i的参数构造 Map param = createParameters(interceptor.param()); //i的名称 String name = interceptor.value(); //通过i的名字去所有的i中查询 i config Object o = pc.getAllInterceptorConfigs().get(name); //查出来的是i config对象 if (o instanceof InterceptorConfig) { InterceptorConfig config = (InterceptorConfig) o; //通过config去加载 真正的 i Interceptor inter = null; try { inter = objectFactory.buildInterceptor(config, param); list.add(new InterceptorMapping(name, inter)); return list; } catch (ConfigurationException ex) { logger.warn("Unable to load config class "+config.getClassName()+" at "+ ex.getLocation()+" probably due to a missing jar, which might "+ "be fine if you never plan to use the "+config.getName()+" interceptor", ex); return list; } //查出来的是i stack config对象,可直接取到i mapping对象 } else if (o instanceof InterceptorStackConfig) { InterceptorStackConfig config = (InterceptorStackConfig) o; list.addAll(config.getInterceptors()); return list; } return list; } /** * 创建result 集合 * @param rs * @param pc * @return */ private Map<String, ResultConfig> createResultConfigs(ActionResults rs, PackageConfig pc) { Map<String, ResultConfig> map = new HashMap<String, ResultConfig>(); if (rs == null) return map; ActionResult ars[] = rs.value(); for (ActionResult ar : ars) { ResultConfig rc = createResultConfig(ar, pc); if (rc != null) map.put(rc.getName(), rc); } return map; } /** * Creates a default ResultConfig, * using either the resultClass or the default ResultType for configuration package * associated this ResultMap class. * * @param key The result type name * @param resultClass The class for the result type * @param location Path to the resource represented by this type * @return A ResultConfig for key mapped to location */ @SuppressWarnings("unchecked") private ResultConfig createResultConfig(ActionResult result, PackageConfig pc) { if (result == null) return null; Map param = createParameters(result.param()); Class clazz = result.type(); //判断是否使用默认的result type,是的话需要去取默认result type的实现类 if (clazz == NullResult.class) { String defaultResultType = pc.getFullDefaultResultType(); ResultTypeConfig resultType = pc.getAllResultTypeConfigs().get(defaultResultType); if (resultType.getParams() != null) param.putAll(resultType.getParams()); try { clazz = Class.forName(resultType.getClazz()); } catch (ClassNotFoundException ex) { } } //设定default param也就是location String defaultParam; try { defaultParam = (String) clazz.getField("DEFAULT_PARAM").get(null); } catch (Exception e) { // not sure why this happened, but let's just use a sensible choice defaultParam = "location"; } param.put(defaultParam, result.value()); //创建result config返回 return new ResultConfig(result.name(), clazz.getName(), param); } /** * 构建param anno参数的map的方法 * @param ps * @return */ private Map<String, Object> createParameters(Param[] ps) { Map<String, Object> map = new HashMap<String, Object>(); if (ps == null) return map; for (Param p: ps) { map.put(p.name(), p.value()); } return map; } }
两个用zero config配置的action的例子,一个简单的,一个复杂
看起来还是比较清晰的
@Action(name = "TeacherList") @ActionResult(value = "/sample/lesson/TeacherList.jsp") public String listTeacher() throws Exception { return SUCCESS; }
@Action(name = "Login") @ActionInterceptors({ @ActionInterceptor("sendTimeoutRequest"), @ActionInterceptor("brickStack") }) @ActionExceptionMappings({ @ActionExceptionMapping(exceptionClass = UserNotExistException.class, result = "UserNotExist"), @ActionExceptionMapping(exceptionClass = PasswordNotAvailException.class, result = "PasswordNotAvail") }) @ActionResults({ @ActionResult(name = "UserNotExist", value = "/sample/lesson/Login.jsp"), @ActionResult(name = "PasswordNotAvail", value = "/sample/lesson/Login.jsp"), @ActionResult(name = "input", value = "/sample/lesson/Login.jsp"), @ActionResult(value = "/sample/lesson/Main.jsp") }) public String login() throws Exception { return SUCCESS; }
评论
14 楼
ta8210
2010-01-10
还是我的老话。
如果将配置文件中的内容,移动到类中做注解。
在谈零配置其实没有什么意义。项目不需要零配置,项目需要简化配置。
如果将配置文件中的内容,移动到类中做注解。
在谈零配置其实没有什么意义。项目不需要零配置,项目需要简化配置。
13 楼
ta8210
2010-01-10
配置文件零化了,但是这不叫零配置。
将配置文件中的内容,移动到类中做注解。这本身就不是零配置。
建议博主在设定几个基本参数之后,一切配置完全由扫描classpath得出。
这样 就可以生成配置来使用。
比方说我有一个 Filter接口,和一个Action接口。 系统扫描所有类将所有实现Filter的实现类都生成过滤器配置,而Action实现类都生成为action配置。
如果某个action单独需要过滤器,这时在通过注解明确指出。如果是通用的则通过PublicFiter策略全局化,在配合 修饰类的注解来解决 例外配置问题。
如果整个项目都是 例外配置,那肯定 都不是例外配置。 需要在做抽象。
至于ioc部分的零配置 spring的自动装配 工作的很好。 可以在做一些优化。
将配置文件中的内容,移动到类中做注解。这本身就不是零配置。
建议博主在设定几个基本参数之后,一切配置完全由扫描classpath得出。
这样 就可以生成配置来使用。
比方说我有一个 Filter接口,和一个Action接口。 系统扫描所有类将所有实现Filter的实现类都生成过滤器配置,而Action实现类都生成为action配置。
如果某个action单独需要过滤器,这时在通过注解明确指出。如果是通用的则通过PublicFiter策略全局化,在配合 修饰类的注解来解决 例外配置问题。
如果整个项目都是 例外配置,那肯定 都不是例外配置。 需要在做抽象。
至于ioc部分的零配置 spring的自动装配 工作的很好。 可以在做一些优化。
12 楼
leeon
2007-09-30
引用
加载有@标记的类:现在实现的是在WEB.XML文件中写出包含有@标记的Action所在的包。但是我觉得在WEB.XML中去写不是很方便,因为在项目中并不是每个人都有权利去修改这个文件。所以我觉得在复写XmlConfigurationProvider的时候最好去struts.xml类中去加载包名。根据包名加载都做好了,那还可以添加一个根据类名加载吧呵呵 ,不是很有必要随便说说。
其实就是因为不是每个人都有权利去修改这个web.xml文件,所以才会想出来配置一个目录,然后系统自动去搜索目录下的包括子目录的所有action类。
项目中只要定好,所有的action类必须在某一个目录下,比如sample.web.action这样的目录,具体各个模块再在这个目录的基础上分子目录,web.xml只要定义该目录sample.web.action就可以了。
也像你说的那样,要扩展struts dtd比较麻烦,我要改struts包中的dtd或者改配置文件上的dtd验证url,这样导致struts的xml不标准,对struts的入侵太厉害,毕竟这样就是修改而不是扩展struts的代码了。
11 楼
leeon
2007-09-30
引用
如果用了@Annotation的话就不能用XML了,所以我建议你不要继承接口而是继承XmlConfigurationProvider类,让同时可以加载xml的配置和@的配置。不同package共用的result Exception还是在struts.xml中配置比较合适。这样的话struts.xml文件还是有存在的必要
这条好像不太对,我们现在就是@annotation和xml一起用,而且正如你想的不同package共用的result Exception, global result, interceptor等等信息都是在struts.xml文件中配置的。
其实struts加载的时候,是先加载XmlConfigurationProvider,再加载自定义的Provider,所以肯定是先加载xml,在加载annotation。
难道你的xml和annotation不能一起用?
10 楼
leeon
2007-09-30
引用
标记@Action的Target类型是METHOD的,为什么不可以写在TYPE和METHOD呢?甚至一个类中的共用的Result,EXCEPTION,INTERCEPOTR也可以写在类上边啊……因为一个Action类中的CRUD方法返回的结果集和处理错误集很有可能返回的结果是一样的。处理异常也可能一样等等。而对于不同的业务处理方法也可能有特殊的返回结果。这样在这个方法前边只标记他特殊的Result Exception什么什么的
这个....我发的东西的版本比我们项目在用的版本早,后来的版本中,result, exception, interceptor都可以定义在class这个级别上,甚至定义在package-info.java中,这样甚至可以一个package下所有的action class共用一些信息,代码没有贴出来
9 楼
leeon
2007-09-30
好久没看,你居然写了这么多...
我条条来回复吧
我条条来回复吧
8 楼
allenBen
2007-09-28
你写的东西比雷声大雨点小的Apache写的Struts2的Annotion爽多了。呵呵 ! 但是我可以根据我的经验和理解提几点建议吧
说的不对的可以拍砖头,目的只有一个,创建一个真正能提高开发效率的Struts2的Annotation
- 标记@Action的Target类型是METHOD的,为什么不可以写在TYPE和METHOD呢?甚至一个类中的共用的Result,EXCEPTION,INTERCEPOTR也可以写在类上边啊……因为一个Action类中的CRUD方法返回的结果集和处理错误集很有可能返回的结果是一样的。处理异常也可能一样等等。而对于不同的业务处理方法也可能有特殊的返回结果。这样在这个方法前边只标记他特殊的Result Exception什么什么的
- 如果用了@Annotation的话就不能用XML了,所以我建议你不要继承接口而是继承XmlConfigurationProvider类,让同时可以加载xml的配置和@的配置。不同package共用的result Exception还是在struts.xml中配置比较合适。这样的话struts.xml文件还是有存在的必要
- 加载有@标记的类:现在实现的是在WEB.XML文件中写出包含有@标记的Action所在的包。但是我觉得在WEB.XML中去写不是很方便,因为在项目中并不是每个人都有权利去修改这个文件。所以我觉得在复写XmlConfigurationProvider的时候最好去struts.xml类中去加载包名。根据包名加载都做好了,那还可以添加一个根据类名加载吧呵呵 ,不是很有必要随便说说。
- 如果在struts.xml中去写包、类名的话就需要特别的标签了。我不知道DTD怎么扩展。Struts用的是DTD验证。
<!ELEMENT annotationed (annotationpkg*,annotationcls*)>
<!ATTLIST annotationpkg
name CDATA #REQUIRED
>
<!ATTLIST annotationcls
name CDATA #REQUIRED
>
说的不对的可以拍砖头,目的只有一个,创建一个真正能提高开发效率的Struts2的Annotation
7 楼
leeon
2007-09-27
,实不实用可能很难说
不过至少写了这个东西后让我对struts2和xwork熟悉了不少
不过至少写了这个东西后让我对struts2和xwork熟悉了不少
6 楼
allenBen
2007-09-27
太感谢你了 你写的这个东西我学习了2天半 终于差不多了
5 楼
leeon
2007-09-26
BeanUtil.java
import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @author leeon * 对类路径上文件操作的一些工具类 */ public class BeanUtil { private static Log logger = LogFactory.getLog(BeanUtil.class); /** * 根据文件所在类路径返回对应的绝对路径的文件对象。 * 该文件的URL是类装载器在类路径上找到的第一个该路径上的文件的URL * @param classPath 文件类路径 * @return 文件URL绝对路径对应的File对象 * @throws FileNotFoundException * @throws UnsupportedEncodingException * @throws URISyntaxException */ public static File getClassPathFile(String classPath) throws FileNotFoundException { URL url = getClassPathFileURL(classPath); if (url != null && "file".equals(url.getProtocol())) try { return new File(url.toURI()); //toURI如果有空格,可能会抛出错误,所以需要进行另外的处理 } catch (URISyntaxException e) { logger.warn("url to URI syntax exception, maybe jdk bug"); logger.warn(e); String p = url.getFile(); if (p.charAt(0) == '/' && p.charAt(2) == ':') p = p.substring(1); return new File(p); } else if (url != null) throw new FileNotFoundException("this file [" + url + "] in class path:[" + classPath + "] not a filesystem file"); else throw new FileNotFoundException("this file not in class path:["+ classPath + "]"); } /** * 根据文件所在类路径返回该文件对应的绝对URLs。 * 该URL数组是类装载器在类路径上找到的所有该路径文件的URL的集合 * URL格式可能是file:/D:/foo/bar/classes/com/guanghua/brick/aaa.class * 也有可能是jar:file:/D:/foo/bar/brick.jar!com/guanghua/brick/aaa.class等等 * @param classPath 文件类路径 * @return 文件所在绝对路径URL的数组 * @throws IOException */ public static URL[] getClassPathFileURLs(String classPath) throws IOException { Enumeration e = Thread.currentThread().getContextClassLoader().getResources(classPath); //将url放入hashset以去掉重复的url HashSet<URL> set = new HashSet<URL>(); while (e.hasMoreElements()) { Object o = e.nextElement(); set.add((URL)o); logger.debug("find file [" + classPath +"] from class path, and url is [" + o + "]"); } return (URL[]) set.toArray(new URL[0]); } /** * 根据文件所在类路径返回该文件对应的绝对URL。 * 该URL是类装载器在类路径上找到的第一个该路径上的文件的URL * URL格式可能是file:/D:/foo/bar/classes/com/guanghua/brick/aaa.class * 也有可能是jar:file:/D:/foo/bar/brick.jar!com/guanghua/brick/aaa.class等等 * @param classPath 文件类路径 * @return 文件所在绝对路径URL * @throws Exception */ public static URL getClassPathFileURL(String classPath) { return Thread.currentThread().getContextClassLoader().getResource(classPath); } /** * 根据文件所在类路径返回对应文件的输入流。 * @param classPath 文件类路径 * @return 该文件的输入流 */ public static InputStream getClassPathFileByInputStream(String classPath) { return Thread.currentThread().getContextClassLoader().getResourceAsStream(classPath); } }
4 楼
leeon
2007-09-26
这两个类全是静态方法
FileUtil.java
FileUtil.java
import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.jar.JarFile; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @author leeon * 对类路径上的文件或者文件系统上的文件进行搜索的工具类 */ public class FileUtil { private static Log logger = LogFactory.getLog(FileUtil.class); /** * 在文件系统的某个目录中搜索符合pattern要求的文件,filePath就是搜索的目录的全路径 * 比如filePath路径是c:/foo/bar,那么就是搜索c:/foo/bar下的所有符合patter格式的文件 * 如果filePath的不是目录或者不存在,那么返回一个空列表。 * @param filePath 需要搜索的目录路径 * @param pattern 文件名(不包括文件路径)符合的模版,正则表达式的模版 * @return 返回搜索到的文件全路径列表 */ public static List<String> searchFileFromFolder(String filePath, String pattern) { return searchFileFromFolder(getFileResource(filePath), pattern, null); } /** * 检查文件系统某个目录下所有名字(非路径,只包括文件名)符合正则表达式pattern要求的文件 * 返回的结果是一个String的列表,可以有两种结果 * 如果prefix为null,列表里的字符串就是符合要求的文件的绝对路径 * 如果prefix不为null,列表里的字符串就是类路径格式的字符串,比如在c:/foo/bar下搜索,prefix为foo1/bar1 * 搜索到一个文件是c:/foo/bar/test/Test.class,那么返回的list中的字符串就是foo1/bar1/test/Test.class * 如果prefix传的是"",那么返回的字符串就是/test/Test.class * @param folder, 开始搜索的文件夹,如果文件夹为空,或者不存在,或者不是文件夹,那么返回空列表 * @param pattern, 搜索用的正则表达式 * @param prefix, 返回类路径或者是文件绝对路径的标志,如果是null,返回文件绝对路径 * @return 返回list,符合list要求的每一个对象是该文件的绝对路径 */ public static List<String> searchFileFromFolder(File folder, final String pattern, String prefix) { List<String> re = new ArrayList<String>(); //给prefix加上/,以便于递归 if (prefix != null && prefix.length() != 0) prefix = prefix + "/"; //当文件夹存在,并且是文件夹时,才进行搜索 if (folder.exists() && folder.isDirectory()) { //获取符合pattern条件的文件列表 File[] files = folder.listFiles(new FileFilter() { public boolean accept(File file) { //如果该文件是隐藏的,不继续寻找 if (file.isHidden()) return false; else { //如果该文件是目录那么继续寻找他的儿子 if (file.isDirectory()) return true; else { //如果不是目录,则检验其文件名是否满足要求 return Pattern.matches(pattern, file.getName()); } } } }); //遍历文件列表,看是否是目录或者文件,是目录就递归,是文件就根据prefix返回 for (int i = 0; files != null && i < files.length; i++) { if (files[i].isDirectory()) { re.addAll(searchFileFromFolder(files[i], pattern, prefix==null?null:prefix+files[i].getName())); } else { //需要返回文件路径 if (prefix == null) re.add(files[i].getAbsolutePath()); //需要返回类路径 else re.add(prefix+files[i].getName()); } } } return re; } /** * 检查zip包中某个目录下的所有文件名(不包括文件路径)符合正则表达式pattern要求的文件 * 返回一个文件类路径的列表. * folderPath是搜索的zip包中的类路径文件夹,prefix是一个其实搜索和返回路径的前缀,主要用于搜索war包时 * 比如一个war包,foo.war,那么zipFile时foo.war的ZipFile,要搜索pattern为*.hbm.xml,搜索的类路径就是com/guanghua/domain,而搜索的前缀就应该是/WEB-INF/classes * 这时候,真正开始搜索的zip包路径是/WEB-INF/classes/com/guanghua/domain,而返回的文件类路径却是com/guanghua/domain/Test.hbm.xml的形式,返回结果会自动截取前缀 * 同样在搜索ear包时,也同理可以这样做。搜索jar包的化,prefix传入""即可 * @param zipFile 被搜索的zip文件 * @param pattern 文件名必须符合的正则表达式的pattern * @param folderPath * @param prefix * @return zip文件夹中所有符合条件的文件的类路径列表 */ public static List<String> searchFileFromZip(ZipFile zipFile, String pattern, String folderPath, String prefix) { List<String> list = new ArrayList<String>(); //拿到zip中所有的entry Enumeration e = zipFile.entries(); folderPath = folderPath.startsWith("/")?prefix+folderPath:prefix+"/"+folderPath; while (e.hasMoreElements()) { ZipEntry zipEntry = (ZipEntry)e.nextElement(); //获取zip中文件的路径 String zip = zipEntry.getName(); zip = zip.startsWith("/")?zip:"/"+zip; //如果zipEntry的开头是prefix,那么说明这是prefix目录下的一个文件 if (!zipEntry.isDirectory() && zip.startsWith(folderPath)) { //获取真实的文件名 String jarFileName = zip.substring(zip.lastIndexOf("/")+1); //文件名符合pattern的要求 if (Pattern.matches(pattern, jarFileName)) list.add(zip.substring(prefix.length()+1)); } } return list; } /** * 在指定的类路径中搜索文件名符合pattern要求的文件 * 比如要搜索com/guanghua/brick下所有符合.hbm.xml结尾的文件就可以使用该方法 * 返回的结果是符合要求的文件的类路径,比如com/guanghua/brick/domain/foo.hbm.xml * @param classPath 指定的类路径 * @param pattern 文件名必须符合的pattern * @return 返回在指定类路径中文件名符合要求的类路径列表 * @throws Exception */ public static List<String> searchFileFromClassPath(String classPath, String pattern) throws IOException { //获取指定的类路径的定位URL URL[] urls = BeanUtil.getClassPathFileURLs(classPath); //返回的是list,但是利用set来保证没有重复的url List<String> list = new ArrayList<String>(); Set<String> set = new HashSet<String>(); //没有找到对应的url list,返回空 if (urls == null) return list; for (int i = 0; i < urls.length; i ++) { //将搜索到的结果放入set set.addAll(searchFileFromClassPath(urls[i], classPath, pattern)); } list.addAll(set); return list; } /** * 根据URL确定搜索文件的路径,然后根据classPath确定搜索的类路径,再搜索文件名符合pattern格式的文件 * classPath所在的位置可能是jar,可能是war,可能是folder,但必须和url的位置一致。 * 在类路径中搜索符合pattern要求的文件 * @param url 搜索的jar包或者文件夹所在的url路径, * @param classPath 搜索的类路径 * @param pattern 文件名符合的模版 * @return 返回在指定类路径中文件名符合要求的类路径列表 * @throws IOException */ public static List<String> searchFileFromClassPath(URL url, String classPath, String pattern) throws IOException { logger.debug("search file type: ["+ pattern +"]"); logger.debug("search file in classpath: ["+ classPath +"]"); logger.debug("the real filepath is : ["+ url +"]"); if (url == null) return new ArrayList<String>(); //处理文件名 String file = url.getFile(); int i = file.indexOf("!"); file = (i != -1)?file.substring(0, i):file; //获取协议 String protocol = url.getProtocol(); //如果类所在的文件路径是jar包 if ("jar".equals(protocol)) { JarURLConnection jc = (JarURLConnection)url.openConnection(); logger.debug("search jar file from :["+ url +"]"); return searchFileFromZip(jc.getJarFile(), pattern, classPath, ""); //如果类所在的文件路径是wsjar包 } else if ("wsjar".equals(protocol)) { //wsjar需要去掉file:/才能在ws下识别 if (file.startsWith("file:/")) file = file.substring(6); logger.debug("search wsjar file from :["+ file +"]"); JarFile jarFile = new JarFile(new File(URLDecoder.decode(file, "UTF-8"))); return searchFileFromZip(jarFile, pattern, classPath, ""); //如果类所在的文件路径是zip包 } else if ("zip".equals(protocol)) { //如果类所在的文件路径是war包 if (file.endsWith("war")) { logger.debug("search war file from :["+ file +"]"); ZipFile zipFile = new ZipFile(new File(URLDecoder.decode(file, "UTF-8"))); return searchFileFromZip(zipFile, pattern, classPath, "/WEB-INF/classes"); //如果类所在的文件路径是普通zip包 } else { logger.debug("search zip file from :["+ file +"]"); ZipFile zipFile = new ZipFile(new File(URLDecoder.decode(file, "UTF-8"))); return searchFileFromZip(zipFile, pattern, classPath, ""); } //如果是普通的文件协议 } else if ("file".equals(protocol)) { logger.debug("search filesystem folder from :["+ url +"]"); return searchFileFromFolder(new File(URLDecoder.decode(url.getFile(), "UTF-8")), pattern, classPath); //其余情况返回空列表 } else return new ArrayList<String>(); } /** * 根据传入文件完整路径,获取文件所在的文件夹路径 * 原理是截取最后一个"/"之前的字符串作为文件夹名称 * @param filePath 文件完整路径 * @return 文件夹名称 */ public static String getFloderName(String filePath) { return filePath.substring(0, filePath.lastIndexOf("/")); } /** * 根据传入的文件完整路径,获取文件的名称 * 原理是截取最后一个"/"之后的字符串作为文件名 * @param filePath 文件完整路径 * @return 文件名 */ public static String getFileName(String filePath) { return filePath.substring(filePath.lastIndexOf("/") + 1); } /** * 根据文件路径(绝对路径)直接返回文件对象。 * 相当于new File(filePath) * @param filePath 文件的绝对路径 * @return 文件对象 */ public static File getFileResource(String filePath) { return new File(filePath); } }
3 楼
allenBen
2007-09-26
那么请问能否帖上来 以免我们自己要再写一遍或者修改实现了
2 楼
leeon
2007-09-26
是我自己写的,呵呵,不好意思
一些小工具类,用来搜索某个类路径下名字符合某个正则表达式的
所有类的方法
嘿嘿,可以无视
一些小工具类,用来搜索某个类路径下名字符合某个正则表达式的
所有类的方法
嘿嘿,可以无视
1 楼
allenBen
2007-09-26
请问FileUtil和BeanUtil是什么类?是那个包下边的类啊?不是老大你自己写的吧!
谢谢
谢谢
发表评论
-
范型是这样的-3
2007-09-27 17:44 1679最后贴一段代码,某高人写的,卡卡 import java ... -
范型是这样的-2
2007-09-27 17:42 2669上篇主要将<D>和<D extends Li ... -
范型是这样的-1
2007-09-27 17:12 5008前一阵在做一个功能的时候,要通过反射去取List的范型定义,所 ... -
打造0配置文件的SSH框架-9
2007-09-22 10:00 1818解决拿methodActionPackage这个大问题 ... -
打造0配置文件的SSH框架-8
2007-09-22 09:50 2127接下来,我们需要在stru ... -
打造0配置文件的SSH框架-7
2007-09-22 09:24 2284首先是定义好我们要用的annotation,定之前,我 ... -
打造0配置文件的SSH框架-6
2007-09-22 09:23 3968最后一块,struts, ... -
打造0配置文件的SSH框架-5
2007-09-02 15:46 3752Spring的可扩展点做得比h ... -
打造0配置文件的SSH框架-4
2007-09-01 21:16 3154很多天没有更新Blog ... -
打造0配置文件的SSH框架-3
2007-08-25 21:31 3396前面一篇说到在hibernate.cfg.xml只配置一 ... -
打造0配置文件的SSH框架-2
2007-08-25 12:17 3253Hibernate的annotation,借用了ejb ... -
打造0配置文件的SSH框架-1
2007-08-25 11:33 3546xml配置文件于现在的J2EE开发中,几乎是不 ...
相关推荐
压缩包"ssh_jar"很可能包含了经过精简后的SSH框架各个组成部分的jar文件,每个文件可能已经去除了冗余或未使用的类和方法。在使用这个精简版的SSH框架时,开发者需要确保所有必要的功能都已包含,并且在遇到新的功能...
在实际开发中,SSH框架结合CRM理念,能够为企业打造一个高效、灵活且易于维护的客户关系管理系统。开发过程中,还需要考虑安全性、性能优化、数据库设计以及用户体验等多个方面,确保系统的稳定性和实用性。同时,...
【标题】"JAVA源码 jsp源代码程序 代码 SSH框架 easyui 进销存管理系统"揭示了这个项目的...通过分析和学习这个项目的源代码,开发者不仅可以提升对SSH框架的理解,也能掌握如何利用EasyUI来打造高效的后台管理系统。
SSH框架,全称为Spring、Struts和Hibernate,是Java Web开发中的经典组合,常用于构建企业级应用。本文将详细讲解如何在Myeclipse 6.0环境下配置SSH框架。 首先,我们需要创建一个新的WEB工程。在Myeclipse中,选择...
Struts2的核心组件包括拦截器(Interceptor)、配置文件(struts.xml)以及一系列插件,这些使得开发者能够灵活控制请求流程,并实现了AOP(面向切面编程)的概念。 Spring框架则是一个全面的企业级应用框架,它...
#### SSH框架集成:打造高效企业级应用 SSH框架的集成为企业级应用开发带来了极大的便利。它们各自扮演着不同的角色,共同构建了一个功能强大、结构清晰的应用系统: 1. **视图层**:Struts负责前端界面的展示,...
通过分析这个项目的源代码,新手可以深入理解SSH框架如何协同工作,以及如何利用Bootstrap来打造现代Web应用。这样的实践项目对于巩固理论知识、提升实际操作技能有着显著的作用,同时也适合作为参与Web开发比赛的...
在本项目中,我们主要探讨的是...通过理解和实践这样的项目,开发者可以深入理解SSH2框架的使用,以及如何结合Ztree和Bootstrap来打造用户友好的界面。同时,对于Oracle数据库的使用和管理也是提升数据库技能的好机会。
SSH框架,全称为Struts2、Hibernate和Spring,是Java Web开发中的一种经典组合,用于构建企业级应用程序。...通过不断学习和实践,开发者可以熟练掌握SSH框架,提高开发效率,打造出高效、稳定的Web应用程序。
**SSH2 框架与 Maven 的整合应用** 在软件开发领域,SSH2(Struts2、Spring 和 Hibernate 2)是一种经典的Java企业级应用程序开发框架组合,它为开发者提供了强大的MVC(Model-View-Controller)架构支持、依赖注入...
通过SSH框架,我们可以快速搭建出一个稳定、高效的博客系统,不仅满足基本的博客功能,还能通过扩展实现更多个性化需求。在实践中,开发者还需要考虑安全性、性能优化、用户体验等方面的问题,以打造更高质量的应用...
SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架。本章节将详细介绍如何在...通过不断的实践和优化,开发者可以更好地利用SSH框架解决实际问题,打造出高质量的Web应用。
SSH框架整合是Java Web开发中常见的一种技术组合,它涵盖了Spring、Struts2和Hibernate这三个主要的开源框架。这些框架分别负责控制层、业务层和数据访问层的管理,为开发者提供了一种高效且可维护的开发模式。下面...
需要注意的是,尽管SSH提供了强大的功能,但其配置较为复杂,尤其是当项目规模增大时,大量的XML配置文件可能导致维护困难。因此,SSH框架的注解实现应运而生,它简化了配置,提高了开发效率,并使代码更加清晰。...
首先,让我们逐一了解SSH框架的核心组件: 1. **Struts**:这是一个基于MVC(Model-View-Controller)设计模式的Web应用框架,主要负责处理HTTP请求,控制应用程序的流程。在超市管理系统中,Struts处理用户从POS机...
SSH(Struts2 + Spring + Hibernate)是一种经典的Java Web开发框架组合,用于构建高效、可维护的Web应用程序。...通过深入理解每个框架的注解用法,可以更好地驾驭SSH框架,打造高效稳定的Web应用。
首先,我们需要了解SSH框架的基本概念。Spring框架提供了一个全面的编程和配置模型,用于简化企业级Java应用的开发。它包括依赖注入、AOP(面向切面编程)、事务管理等功能。Struts则是一个MVC(模型-视图-控制器)...
SSH框架的整合,使得开发人员能够更高效地构建可扩展且易于维护的Web应用。 ### Struts2:控制层 Struts2作为MVC架构中的控制层,负责接收HTTP请求,解析请求参数,调用业务逻辑,并将处理结果转发到相应的视图...
SSH开发电影管理系统是一种基于Java技术的Web应用框架组合,由Struts2、Spring和Hibernate三个开源框架集成。这个系统主要用于实现在线影院的功能,允许用户在线浏览、搜索和观看电影,同时还可能包括用户管理、评论...
在这个项目中,我们将深入探讨SSH框架在构建BBS论坛系统中的应用。 1. **Spring框架**:Spring是核心的依赖注入(DI)和面向切面编程(AOP)框架,它简化了Java企业级应用的开发。在BBS论坛系统中,Spring可以管理...