java 上传文件注意事项

java 上传文件注意事项

1、文件名有特殊字符的情况,所以最好是文件名前台url编码,后台再url解码,这点在下载的时候也一样
2、文件大小一定要设置,spring boot 有默认。
3、文件名校验:
3.1、文件后缀校验
3.2、content-type校验
3.3、通过文件流,校验文件头,真实校验

其中,单纯的文件后缀和content-type校验,容易被绕过,只有文件流才能真实的判断出这个文件是什么类型的。
一般的做法就是先通过后缀过滤,绝大部分请求还是正常人
然后再通过流截取文件头信息,判断文件的真实类型。

特别注意: txt文本文档时没有头的,所以不能通过判断头来过滤,以下是网友的一些建议,摘过来供参考:

bmp,jpg等图象文件,可以判断文件头,来确定它的文件类型
但txt没有文件头的,无法判断它是否是txt文件
所以,只能分析文件中所有数据,看看是不是都是可以显示的字符
如果都是可以显示的字符,说明它可以当作txt文件进行阅读,否则,会有乱码出现
这显然要先了解一下什么是文本类的文件,其实说白了,就是ACSII码文件。二进制文件与文本文件的显著差别在于:二进制文件中可能会出现数目众多的0,而文本文件中则不会有,因为文本文件中除了一些特殊的控制字符(比如\n,\r,\t)以外,都是可见字符。
补充1:
除了.txt文件以外,其它的各种文件似乎都会有二进制文件头,这些文件头都很特别,比如0xFEFE、0xFDFD等等。必须说明的一点是.doc文件严格的说,它不应该是一个文本文件,因为它内部有大量的不可见的控制字符,而且最关键的是,它内部允许包含0,并且它有二进制的头数据块。
如果你真想鉴别所有的,你所期望的文本类文件的话,比如.txt、.doc这些文件,你就必须了解这些文件的文件格式,当然.txt是没有固定格式的,但它有一个特征是,不会含有0。
补充2:
对于unicode的文本文件来说,它也是有文件头的,根据大小尾的不同,分别是FFFE和FEFF,严格的说,unicode的文件,不能说是文本文件。
回到你的补充问题,如果想确认一个文件是不是文本文件,加入说是ANSI的,你可以遍历整个文件,看是否存在0,如果没有那么就是了,如果具有FFFE或者FEFF文件头的unicode文件,那么你所关注的对象是,00,也就是两个连续的0。

个人认为,
要么就是把所有可能的文件后缀都放在那个判断的map中(下面代码中会初始化),然后再拿不到就认为是txt类型
要么就是遍历整个文件,看是否存在0,没有就是txt

下面是相关代码:


@Slf4j
public class FileCheckUtil {// 缓存文件头信息-文件头信息private static final HashMap<String, String> MFILETYPES = new HashMap<String, String>();static {//pdf,word,excel,pptMFILETYPES.put("25504446", "pdf");MFILETYPES.put("255044462D312E", "pdf");MFILETYPES.put("D0CF11E0", "xls");//ppt、doc、xls 2003版本文件MFILETYPES.put("504B0304", "xlsx");//pptx、docx、xlsx 2007以上版本文件// imagesMFILETYPES.put("FFD8FFE0", "jpg");MFILETYPES.put("FFD8FF", "jpg");MFILETYPES.put("89504E47", "png");MFILETYPES.put("47494638", "gif");MFILETYPES.put("49492A00", "tif");MFILETYPES.put("424D", "bmp");// CADMFILETYPES.put("41433130", "dwg");//音视频MFILETYPES.put("57415645", "wav");MFILETYPES.put("41564920", "avi");MFILETYPES.put("2E524D46", "rm");MFILETYPES.put("000001BA", "mpg");MFILETYPES.put("000001B3", "mpg");MFILETYPES.put("6D6F6F76", "mov");MFILETYPES.put("3026B2758E66CF11", "asf");//其他MFILETYPES.put("38425053", "psd");MFILETYPES.put("7B5C727466", "rtf"); // 日记本MFILETYPES.put("3C3F786D6C", "xml");MFILETYPES.put("68746D6C3E", "html");MFILETYPES.put("44656C69766572792D646174653A", "eml"); // 邮件MFILETYPES.put("5374616E64617264204A", "mdb");MFILETYPES.put("252150532D41646F6265", "ps");MFILETYPES.put("52617221", "rar");MFILETYPES.put("4D546864", "mid");MFILETYPES.put("1F8B08", "gz");}public static String getRealFileType(FileInputStream is) {return MFILETYPES.get(getFileHeader(is));}public static String getFileHeader(FileInputStream is) {String value = null;try {byte[] b = new byte[4];/** int read() 从此输入流中读取一个数据字节。int read(byte[] b) 从此输入流中将最多 b.length* 个字节的数据读入一个 byte 数组中。 int read(byte[] b, int off, int len)* 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。*/int read = is.read(b, 0, b.length);log.debug("read:{}", read);value = bytesToHexString(b);} catch (Exception e) {} finally {if (null != is) {try {is.close();} catch (IOException e) {}}}return value;}private static String bytesToHexString(byte[] src) {StringBuilder builder = new StringBuilder();if (src == null || src.length <= 0) {return null;}String hv;for (int i = 0; i < src.length; i++) {// 以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式,并转换为大写hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();if (hv.length() < 2) {builder.append(0);}builder.append(hv);}log.debug("builder.toString()={}", builder.toString());return builder.toString();}public static void main(String[] args) throws Exception {//        final String fileType = getRealFileType(new FileInputStream("D:\\ccc2007.doc"));
//        System.out.println(fileType);}
}

正式的controller:

	//提前定义支持的后缀类型private static final List<String> FILETYPELIST = Arrays.asList("txt", "doc", "docx", "xls", "xlsx", "pdf");@PostMapping(value = "/upload")public BaseResponseDTO uploadFile(@RequestParam("file") MultipartFile file) throws IOException {BaseResponseDTO data = checkFile(file);if (data != null) {return data;}// 获取文件名String originalFilename = file.getOriginalFilename();long now = System.currentTimeMillis();//文件名是以时间戳_真实文件名存储的originalFilename = now + "_" + originalFilename;// 设置文件存储路径String filePath = "/app/upload/";String path = filePath + originalFilename;File dest = new File(path);file.transferTo(dest);// 文件写入return new BaseResponseDTO<>(HTTPState.OK.getCode(), HTTPState.OK.getMsg(), originalFilename);}private String checkFile(MultipartFile file) throws IOException {//校验文件为空if (file.isEmpty()) {return "error";}//简单校验后缀String fileName = file.getOriginalFilename();if (fileName != null) {String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);log.debug("suffix:" + suffix);if (!FILETYPELIST.contains(suffix)) {return "error";}}//校验文件真实类型String fileType = FileCheckUtil.getRealFileType((FileInputStream) file.getInputStream());log.debug("fileType:" + fileType);if (fileType != null && !FILETYPELIST.contains(fileType)) {return "error";}return null;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499826.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[设计模式] ------ 装饰模式

首先&#xff0c;假设项目有个核心功能。 随着项目迭代&#xff0c;又产生功能1和功能2 于是有如下需求&#xff1a; 某个场景需要核心功能和功能1组合&#xff0c; 某个场景需要核心功能和功能2组合&#xff0c; 某个场景需要核心功能和功能1和功能2组合&#xff0c; 甚至以后…

hash和一致性hash

hash&#xff1b;简单的hash取余 优点&#xff1a; 计算简单&#xff0c;快速定位 缺点&#xff1a; 容错和扩展差&#xff0c;任何的增加机器或减少机器&#xff0c;都会伴随着重新set值 比如原来有五台机器做缓存&#xff0c;现在加一台&#xff0c;那么余5就变成余6&#x…

[记录]---mysql数据库,decimal类型设置默认值0,不要是null

mysql数据库 类型为decimal的字段&#xff0c;最好把默认值设置为0&#xff0c;不要设置为null。 因为null值在代码中及其容易造成空指针。

Java 线程状态---WAITING(部分转载)

看到一篇关于写线程waiting状态的文章&#xff0c;感觉很生动有趣&#xff0c;转过来保存下。 总结&#xff1a; waiting这个状态&#xff0c;就是等待&#xff0c;明确了等待&#xff0c;就不会抢资源了。 一个线程A在拿到锁但不满足执行条件的时候&#xff0c;需要另一个线…

[记录] --- linux上项目

1.安装jdk8 yum -y list java* 查看可安装java版本 yum install -y java-1.8.0-openjdk-devel.x86_64 java -version jdk在/usr/lib/jvm目录 2.配置环境变量 打开/etc/profile 在profile文件末尾加入: export JAVA_HOME/usr/lib/jvm/java-1.8.0 export PATH$JAVA_HOME/bin:…

[记录] --- linux安装redis

获取redis资源 wget http://download.redis.io/releases/redis-具体版本.tar.gz 解压 tar xzvf redis-具体版本.tar.gz 安装 cd redis-4.0.8 make&#xff08;这个需要安装了gcc,没有gcc的先执行这个命令:yum install gcc&#xff09; cd src mkdir /usr/local/redis/etc&…

服务端高并发分布式架构演进之路(转载,图画的好)

这个文章基本上从单机版到最终版&#xff0c;经历了加缓存&#xff0c;加机器&#xff0c;高可用&#xff0c;分布式&#xff0c;最后到云等过程&#xff0c;其实我一直想总结一套类似的东西&#xff0c;没想到有人已经先弄出来了&#xff0c;那就不重复造轮子了&#xff0c;而…

java 记录一个类加载顺序的坑

看看这个&#xff0c;先想想结果打印的顺序和a、b的值 public class ClassLoderTest {public static void main(String[] args) {staticFun();}static ClassLoderTest clt new ClassLoderTest();static {System.out.println(1);}{System.out.println(2);}ClassLoderTest(){Sy…

[前端记录] --- vue axios 等调用完再执行后面的语句

vue 整合echarts的时候&#xff0c;是先axios 调用后台接口&#xff0c;获取数据&#xff0c;再将数据渲染到页面。 一开始的问题是&#xff1a;第一次请求完&#xff0c;页面没数据&#xff0c;再请求一次才出现数据 分析到最后&#xff0c;发下是由于axios是异步请求的&…

docker容器核心技术点

docker容器核心技术点&#xff1a; 容器其实本质上就是一个进程&#xff0c;只不过容器的进程是比较特殊的。 容器技术的核心功能&#xff0c;就是通过约束和修改进程的动态表现&#xff0c;创造出一个“边界”&#xff0c;通过“障眼法”让人觉得它是一个独立的系统。大多数容…

spring-boot 一款无侵入型,轻量级的接口文档生成工具apiggs

spring-boot 一款无侵入型&#xff0c;轻量级的接口文档生成工具apiggs 名字叫&#xff1a;apiggs 使用只需两步&#xff0c;先把插件代码引入pom文件&#xff0c;然后编译打包即可 之后项目的target目录下&#xff0c;就会多出一个apiggs的文件夹&#xff0c;里面便是项目cont…

亚马逊S3文件存储的可视化

windos图形化工具下载&#xff1a;http://s3browser.com/ 类似于用xftp操作linux文件一样方便直观清晰

为什么CAP不能同时满足的简单理解

为什么CAP不能同时满足的简单理解 cap定理&#xff1a;前提是分布式系统中&#xff0c;cap三个只能满足两个&#xff0c;不能同时满足三个特性。 Consistency (一致性)&#xff1a;所有节点在同一时间的数据都是完全一致的。 Availability (可用性)&#xff1a;服务一直是可用…

Spring的@Scheduled 动态更新cron表达式

常见的本地定时写法如下&#xff1a; Scheduled(cron "0/5 * * * * ?")private void test() {log.info("业务处理逻辑。。。5秒一次");}如果想要动态更新cron表达式&#xff0c;可以这样写&#xff1a; 先写一个类&#xff0c;让cron表达式总是读成员变量…

spring boot 整合 谷歌guava的EventBus 实现单机版的消息发布订阅

spring boot 整合 谷歌guava的EventBus 实现单机版的消息发布订阅 大型分布式系统&#xff0c;直接用mq解耦&#xff0c;那么单机系统怎么办&#xff0c;可以考虑用EventBus 用EventBus的好处也是异步解耦&#xff0c;和mq的类似&#xff0c;可以勉强认为是单机版的mq 先解释…

我们的java项目,要不要废弃switch

java项目中要不要废弃使用switch 先看switch是怎么产生的&#xff1a; 很久以前&#xff0c;计算能力很昂贵&#xff0c;电脑性能很差&#xff0c;人们便想着法子的提高执行效率 先看看if(test0)的处理逻辑&#xff1a; 先是把test的值放在一个寄存器中&#xff0c;然后把0放…

限流算法(漏桶算法、令牌桶算法)对比

限流算法&#xff08;漏桶算法、令牌桶算法&#xff09; 漏桶算法&#xff1a; 有个桶&#xff0c;比如最大能进2个单位的水&#xff08;请求&#xff09;&#xff0c;桶底有个洞&#xff0c;每个单位的水都会在桶里待3秒后漏下去。 那么这个桶就可以同时处理2个单位的水。 如…

guns框架

分享一个框架guns https://gitee.com/naan1993/guns/ 这算是国内比较优秀的框架&#xff0c;简单的套路都有。 权限啊&#xff0c;代码自动生成啊等等 快速搭建一套后台管理项目 下面是作者介绍&#xff1a; Guns基于Spring Boot2&#xff0c;致力于做更简洁的后台管理系统。…

URLDecoder: Illegal hex characters in escape (%) pattern ...

URL中含有%&#xff0c;报错如下&#xff1a; URLDecoder: Illegal hex characters in escape (%) pattern … 解决&#xff1a; uriStr uriStr.replaceAll("%","%25"); 这种情况一般是出现在连接mongoDB数据库的时候&#xff0c;因为要把用户名密码写…