【前言】
文件上传走到后台的时候需要填充文件的类型、不同的类型对文件大小有不同的限制,这个if写的话很快但是不太好,想起了策略模式,上网查了一些资料,网上的资料挺多但是…… 怎么说? 看博客或者论坛 感觉思路清晰、逻辑连贯、一气呵成、无可挑剔、只要照着敲也就OK了、顿时心情也大好,但是常常在自己电脑上要出些小惊喜
【正文】
之前写过类似的博客,当然只是说了想法和思路,今天就来代码实践一下吧(本脑跑成功了,泥萌的—自求多福)
首先将上传资源的分类提取出来结合自定义的类型和标明此类文件最大值的字段
上面的主体是我自定义的注解,下面以音频为例看一下文件类型相关的类
@ResourceVerify(maxSize =10485760,type = "audio")//自定义注解
public class Audio implements Type {
@Override
public String typeName() {
return "音频".trim();
}
}
判断文件类型及大小,如果符合要求则返回文件类型名称:
package com.giska.resource.tool;
import com.giska.resource.tool.type.ResourceVerify;
import com.giska.resource.tool.type.Type;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018/5/25.
*/
@Component
public class GetType {
private String packageName = "com.giska.resource.tool.type";//上面所述对象所在的包,需要读取包下的类
private ClassLoader classLoader = getClass().getClassLoader();
//策略列表
private List<Class<? extends Type>> typeList;
public String resourceType(File file) throws IOException {
Path path = Paths.get(file.getPath());//获取文件的路径
String contentType = Files.probeContentType(path);//根据路径获取文件的contentType audio vudio image ……
//遍历策略列表
for (Class<? extends Type> type : typeList) {
//获取该策略的注解
ResourceVerify resourceVerify = handleAnnotation(type,contentType);
if( contentType.contains(resourceVerify.type())){//判断是否是当前Type类的类型
//是的话我们返回一个当前策略的实例 名称
if (file.length() < resourceVerify.maxSize()) {
try {
return type.newInstance().typeName();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("获取类型失败");
}
}else {
return "资源大小超过限制了!";
}
}
}
throw new RuntimeException("获取类型失败");
}
/**
* 处理注解,我们传入一个策略类,返回它的注解
*
* @param type
* @return
*/
private ResourceVerify handleAnnotation(Class<? extends Type> type,String contentType) {
Annotation[] annotations = type.getDeclaredAnnotations();//获取类上的注解
if (annotations == null || annotations.length == 0) {
return null;
}
for (int i = 0; i < annotations.length; i++) {
if (annotations[i] instanceof ResourceVerify) {
return (ResourceVerify) annotations[i];//返回注解
}
}
return null;
}
public GetType() throws Exception {
typeList = new ArrayList<Class<? extends Type>>();
List<Class<?>> list = null;
File[] resource = getResource(list);//获取文件列表
Class<Type> typeClass = null;
//使用相同的加载器加载策略接口
try {
typeClass = (Class<Type>) classLoader.loadClass(Type.class.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException("未找到资源类型");
}
for (int i = 0; i < resource.length; i++) {
try {
//载入包下的类
Class<?> clss = classLoader.loadClass(packageName + "." + resource[i].getName().replace(".java", ""));
//判断是否是CalPrice的实现类并且不是CalPrice它本身,满足的话加入到策略列表
if (Type.class.isAssignableFrom(clss) && clss != typeClass) {
typeList.add((Class<? extends Type>) clss);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
/**
* 扫描包下所有的class文件
*
* @return
*/
private File[] getResource(List<Class<?>> list) throws Exception {
File file = new File("");
String path = file.getCanonicalPath() + File.separator + "src\\main\\java." + packageToDir();
File dir = new File(path);
return dir.listFiles();
}
public String packageToDir() {
String[] array = packageName.split("\\.");//写成路径的形式
StringBuffer sb = new StringBuffer();
for (String s : array) {
sb.append(File.separator).append(s);
}
return sb.toString();
}
}
开始获取包下的文件很是费劲,查了一下东西,记录下来:
File.
list()返回某个目录下所有文件和目录的文件名,返回string数组
listFiles()返回某个目录下所有文件和目录的绝对路径,返回file数组
https://www.cnblogs.com/keyi/p/6293141.html
Separator:用来分隔同一路径字符串中的目录,window下路径分隔符\和Linux的/是不一样的
考虑跨平台:File myFile = new File("C:" + File.separator + "tmp" + File.separator, "test.txt");
pathSeparatorChar:与系统有关的路径分隔符,用于分隔以路径列表形式给定的文件序列中的文件名,unix系统字段为: windows为;
https://blog.csdn.net/chindroid/article/details/7735832
https://blog.csdn.net/spy19881201/article/details/6218722
简单来说separator是 \ 或 / pathSeparatorChar是; 或 : 分平台
getPath()返回的是构造方法里的路径,不做任何处理
getAbsolutePath()返回的是执行路径加上构造方法中的路径
getCanonicalPath()返回的是将符号完全解析的路径,也就是全路径
File f = new File("..\\src\\file");
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
//打印结果
..\src\file
C:\workspace\Tip\..\src\file
C:\workspace\src\file
https://www.cnblogs.com/xulianbo/archive/2011/08/26/2154027.html
修改2018年5月29日09:26:45
getCanonicalPath()这个单元测试的时候是可以的,上图为证:
但是项目起的时候报空指针,开始还以为是注入好,调试的时候发现是没有获取上面的这些类,往上倒路径不对、没有确认过原因 单元测试路径如下、项目中的路径很奇怪为什么就不是了呐?清缓存重启也不行
无奈路径写死,可以了、这样要是不可以、那只能是人品太好的原因了
private String getSrcPath() throws Exception { File file = new File("E:\\item\\giska-springboot-resource"); return file.getCanonicalPath() + File.separator + "src\\main\\java"; }
isFile():当且仅当此抽象路径名表示的文件存在且是一个标准文件时,返回true;否则返回false;
Exists()当且仅当此抽象路径名表示的文件或目录存在时,返回true;否则返回false;
isFile():判断是否文件,也许可能是文件或者目录
exists():判断是否存在,可能不存在
isDirectory()是检查一个对象是否是文件夹,如果是返回true,否则返回false。
调用方法为:对象.isDirectory() 无需指定参数。
https://www.cnblogs.com/zhengbiyu/p/8391201.html
论坛 :https://bbs.csdn.net/topics/390716276 获取包下的类
【小结】
设计模式很好的解耦,以后添加类型也不需要动代码,但是目测类型改动可能性很小,增加的这些类隐隐滴让偶感觉不安,那几个异常也是格外滴刺眼,有一句话叫做“如果你感觉有bug的地方那一定有bug”
the world of demo