首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java文件上传实例并解决跨域问题

Java文件上传实例并解决跨域问题

原创
作者头像
曾高飞
修改于 2021-09-10 09:54:29
修改于 2021-09-10 09:54:29
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传功能的实现。

了解MultipartFile接口 我们实现文件的上传用到了Spring-web框架中的 MultipartFile接口,MultipartFile接口的源码注释中说“MultipartFile接口是 在大部分请求中接收的上载文件的表示形式。”

A representation of an uploaded file received in a multipart request. The file contents are either stored in memory or temporarily on disk. In either case, the user is responsible for copying file contents to a session-level or persistent store as and if desired. The temporary storage will be cleared at the end of request processing.

常用方法如下表

Method Summary byte[] 获取文件的字节数组 getBytes()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return the contents of the file as an array of bytes.

String 获取文件的类型 getContentType()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return the content type of the file.

InputStream 获取文件的输入流 getInputStream()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return an InputStream to read the contents of the file from.

String 获取文件名 getName()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return the name of the parameter in the multipart form.

String 获取原始文件名(防止篡改文件类型) getOriginalFilename()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return the original filename in the client's filesystem.

long 获取文件的大小,以字节的形式) getSize()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return the size of the file in bytes.

boolean 判断文件是否为空 isEmpty()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Return whether the uploaded file is empty, that is, either no file has been chosen in the multipart form or the chosen file has no content.

void 将接收到的文件传输到给定的目标文件。 transferTo(File dest)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Transfer the received file to the given destination file.

文件上传业务代码 Controller类 /**

  • @Author: 富贵论坛www.fgba.net
  • @Date: 2021/7/6 - 20:56
  • @Description: 文件上传
  • @version: 1.0

*/ @Controller @RequestMapping("upload") public class UploadController {

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Autowired
private UploadService uploadService;

@PostMapping("image")
public ResponseEntity<String> uploadImage(@RequestParam("file") MultipartFile file){
   String url= this.uploadService.uploadImage(file);
   if (StringUtils.isBlank(url)){
       return ResponseEntity.badRequest().build();
   }
    return ResponseEntity.status(HttpStatus.CREATED).body(url);
}

} Service类:写了具体的业务逻辑 /**

  • @Author: 富贵论坛www.fgba.net
  • @Date: 2021/7/6 - 21:01
  • @Description: 文件上传
  • @version: 1.0

*/ @Service public class UploadService {

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//用于判断文件的类型,暂时只判断了“image/gif","image/jpeg”
private static final List<String> CONTENT_TYPES= Arrays.asList("image/gif","image/jpeg");

private static final Logger LOGGER= LoggerFactory.getLogger(UploadService.class);

/**
 * 业务逻辑代码
 * @param file 文件的存储的url
 * @return
 */
public String uploadImage(MultipartFile file) {

    String originalFilename = file.getOriginalFilename();
    //校验文件类型
    //方法一:截取字符串
    String afterLast = StringUtils.substringAfterLast(".", originalFilename);
    //方法二:使用getContentType方法
    String contentType = file.getContentType();
    if (!CONTENT_TYPES.contains(contentType)){
        LOGGER.info("文件类型不合法:"+originalFilename);
        return null;
    }
    //校验文件内容
    try {
        //获取文件流
        BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
        if (bufferedImage==null){
            LOGGER.info("文件内容不合法:{}",originalFilename);
            return null;
        }
        //保存到服务器   E:\fgba\image
        //将接收到的文件传输到给定的目标文件。
        file.transferTo(new File("E:\\fgba\\Image\\"+originalFilename));
        
        //返回URL,进行回显
        //可以使用Nginx-图片服务器
        return "fgba"+originalFilename;
    } catch (Exception e) {
        LOGGER.info("服务器内部错误:"+originalFilename);
        e.printStackTrace();
    }
    return null;
}

} 修改nginx配置,将文件存储到文件服务器中 修改Nginx的配置文件nginx.conf,监听80端口,设置root的值为:E盘

  • 图片不能保存在服务器内部,这样会对服务器产生额外的加载负担
  • 一般静态资源都应该使用独立域名,这样访问静态资源时不会携带一些不必要的cookie,减小请求的数据量

server {

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    listen       80;
    server_name  ;

    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    location / {
        root E:\\fgba\\image;
    }
}

每次上传文件都会经过网关,必然会给网关带来很大的压力,那我们如何绕过网关呢? 1.在网关中配置白名单 ,这样也会走网关,只是压力少了一点点 @Slf4j public class AuthorizeFilter implements GlobalFilter, Ordered {

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//白名单:存放放行的URL
private List<String> allowPaths;


@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
   
    //获取请求的url路径
    String path = request.getURI().getPath();
    boolean flag=isAllowPath(path);
    if (flag) {
        log.info("请求在白名单中,fgba.filter: {}",path);
        //放行
        return chain.filter(exchange);
    } else {
      //写其他的业务逻辑
        ~~~~
        
    }
}

private boolean isAllowPath(String path) {
 
      //判断是否允许放行
     if (allowPaths.contains(path)){
         return true;
     }
     return  false;

} 2.在nginx做转发,当请求文件上传时,直接转到相应的服务 本实例使用了方法二、需要增加配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server {
    listen       80;
    server_name  fgba;

    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 新增加的配置,用于文件上传
    location /api/upload {
        proxy_pass;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
        
        rewrite "^/api/(.*)$" /$1 break;
    }
    # 网关的配置
    location / {
        proxy_pass;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
    }
}

当这样配置之后,文件上传就不会过网关,减少了网关的压力。但是有引来了一个新问题那就是跨域。

解决上传文件出现跨域问题 由于Nginx将文件上传的请求直接转发到了具体服务中,不再走gateway,所以gateway中的跨域配置,不再生效了。 需要在文件上传这个服务中单独配置跨域。

写配置类CorsFilter /**

  • @Author: 富贵论坛www.fgba.net
  • @Date: 2021/6/15 - 11:12
  • @Description: 解决 跨域问题
  • @version: 1.0

*/ @Configuration public class fgbaCorsConfiguration {

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Bean
public CorsFilter corsFilter(){
    //初始化配置对象
    CorsConfiguration configuration = new CorsConfiguration();
    //允许跨域访问的域名
    configuration.addAllowedOrigin("*");
   // configuration.setAllowCredentials(true);  //运行携带cookie
    configuration.addAllowedMethod("*"); //代表所有请求方法
    configuration.addAllowedHeader("*"); //允许携带任何头信息

    //初始化cors配置源对象
    UrlBasedCorsConfigurationSource configurationSource=new UrlBasedCorsConfigurationSource();
    configurationSource.registerCorsConfiguration("/**",configuration);

    //返回CorSfilter实例,参数
    return new CorsFilter(configurationSource);
}

} 到此应该就可以上传了,但是还是报跨域,我已经配置好了啊,为什么还是报跨域呢?

在nginx配置中配置请求实体大小 我就想是不是Nginx的问题,然后我就一行一行的读配置,最后发现

nginx配置中没有配置请求实体大小

加上这行配置就好了 client_max_body_size 1024m;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
TypeScript 2.8下的终极React组件模式
如果你了解我,你就已经知道我不编写没有类型定义的javascript代码,所以我从0.9版本后,就非常喜欢TypeScript了。除了有类型的JS,我也非常喜欢React库,所以当把React和Typescript 结合在一起后,对我来说就像置身天堂一样:)。整个应用程序和虚拟DOM中的完整的类型安全,是非常奇妙和开心的。
前端迷
2019/07/23
7K0
TypeScript 2.8下的终极React组件模式
React+TypeScript使用规范
一个采用 parameterName is Type的形式返回 boolean 值的函数,但 parameterName 必须是当前函数的参数名
用户4619307
2023/05/04
4.9K0
三千字讲清TypeScript与React的实战技巧
很多时候虽然我们了解了TypeScript相关的基础知识,但是这不足以保证我们在实际项目中可以灵活运用,比如现在绝大部分前端开发者的项目都是依赖于框架的,因此我们需要来讲一下React与TypeScript应该如何结合运用。
桃翁
2019/09/17
2.5K0
useTypescript-React Hooks和TypeScript完全指南
React v16.8 引入了 Hooks,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。这些功能可以在应用程序中的各个组件之间使用,从而易于共享逻辑。Hook 令人兴奋并迅速被采用,React 团队甚至想象它们最终将替换类组件。
前端森林
2020/04/23
9.6K0
useTypescript-React Hooks和TypeScript完全指南
入门 TypeScript 编写 React
Create React App 是一个官方支持的创建 React 单页应用程序的CLI,它提供了一个零配置的现代构建设置。当你使用 Create React App 来创建一个新的 TypeScript React 工程时,你可以运行:
icepy
2019/06/24
5.5K0
React + TypeScript 实践
需要添加额外的配置:"allowSyntheticDefaultImports": true
公众号@魔术师卡颂
2021/05/08
6.8K0
面试官:说说如何在React项目中应用TypeScript?
单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的
winty
2021/10/11
7570
面试官:说说如何在React项目中应用TypeScript?
React-hooks+TypeScript最佳实战
如果新的 state 需要通过使用先前的 state 计算得出,那么可以将回调函数当做参数传递给 setState。该回调函数将接收先前的 state,并返回一个更新后的值。
xiaofeng123aa
2022/10/17
6.4K0
Typescript配合React实践
使用ts写React代码写了将近三个月,从刚开始觉得特别垃圾到现在觉得没有ts不行的一些实践以及思考。如果按部就班的写React就体会不到使用ts的乐趣,如果多对代码进行优化,进行重构,在业务中实践比较好的一些方案就会体会到ts真正的乐趣,但是ts也在过程中给我带来了痛苦,在本文的最后会具体展开一下。
前端迷
2019/07/27
1K0
React Hooks-useTypescript!
在React v16.8新增了Hook,它提供了在函数组件中访问状态和React生命周期等能力,这些函数可以在程序的各个组件之间复用,达到共享逻辑的目的。
写代码的阿宗
2020/09/22
4.3K0
你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript 是如何较优雅的融入 React 项目的。
xiaofeng123aa
2022/10/03
3.3K0
React组件设计实践总结01 - 类型检查
最近准备培训新人, 为了方便新人较快入手 React 开发并编写高质量的组件代码, 我根据自己的实践经验对React 组件设计的相关实践和规范整理了一些文档, 将部分章节分享了出来. 由于经验有限, 文章可能会有某些错误, 希望大家指出, 互相交流.
_sx_
2019/08/07
8.4K0
React组件设计实践总结01 - 类型检查
🔖TypeScript 备忘录:如何在 React 中完美运用?
一直以来,ssh 身边都有很多小伙伴对 TS 如何在 React 中运用有很多困惑,他们开始慢慢讨厌 TS,觉得各种莫名其妙的问题降低了开发的效率。
ssh_晨曦时梦见兮
2022/03/09
3.1K0
🔖TypeScript 备忘录:如何在 React 中完美运用?
TypeScript:React、拖拽、实践!
最后抛开规则的学习,最重要的应该是什么?毫无疑问,是实践。这也是无法从官方文档获取到的重要讯息。
用户6901603
2020/07/23
2.5K0
前端应该掌握的Typescript基础知识
js 是一门动态弱类型语言, 我门可以随意的给变量赋不同类型的值 ts 是拥有类型检查系统的 javascript 超集, 提供了对 es6 的支持, 可以编译成纯 javascript,运行在任何浏览器上。 TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。
前端老鸟
2022/03/07
7060
优雅的在 react 中使用 TypeScript
这是因为我们使用 class properties 语法对state做初始化时,会覆盖掉Component中对state的readonly标识。
西南_张家辉
2021/02/02
3K0
JSX_TypeScript笔记17
TypeScript 也支持JSX,除了能够像Babel一样把 JSX 编译成 JavaScript 外,还提供了类型检查
ayqy贾杰
2019/06/12
2.5K0
JSX_TypeScript笔记17
类型即正义:TypeScript 从入门到实践(三):类型别名和类
学习了注解函数,又了解了类型运算如联合类型和交叉类型,接下来我们来了解一些 TS 中独有的类型别名,它类似 JS 变量,是类型变量,接着我们还会学习 TS 中内容非常庞杂的内容之一:类,了解 TS 中类的独有特性,以及如何注解类,甚至用类去注解其他内容。
一只图雀
2020/04/17
2.9K0
类型即正义:TypeScript 从入门到实践(三):类型别名和类
用TypeScript编写React的最佳实践
如今, React 和 TypeScript 是许多开发人员正在使用的两种很棒的技术。但是把他们结合起来使用就变得很棘手了,有时很难找到正确的答案。不要担心,本文我们来总结一下两者结合使用的最佳实践。
ConardLi
2020/06/04
5K0
[译] 使用 TypeScript 开发 React Hooks
原文:https://www.toptal.com/react/react-hooks-typescript-example
江米小枣
2020/07/23
2.2K0
[译] 使用 TypeScript 开发 React Hooks
相关推荐
TypeScript 2.8下的终极React组件模式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档