微信小程序上传图片 + 后端代码(Java)

微信小程序 - 前端

其中主要用到的两个API,wx.chooseImage(选择图片)和wx.uploadFile(将本地资源上传到服务器)

地址:微信小程序开发文档

  1. wx.chooseImage

    从本地相册选择图片或使用相机拍照。

    代码示例:

    wx.chooseImage({
      count: 1, // 最多可以选择的图片张数
      sizeType: ['original', 'compressed'], // 所选图片的尺寸
      sourceType: ['album', 'camera'], // 选择图片的来源(从相机选图/使用相机)
      success (res) {
        // tempFilePath可以作为img标签的src属性显示图片
        const tempFilePaths = res.tempFilePaths
      }
    })
    
  2. wx.chooseImage

    将本地资源上传到服务器。客户端发起一个HTTPS POST请求,其中content-typemultipart/form-data

    代码示例:

    wx.chooseImage({
     success (res) {
       const tempFilePaths = res.tempFilePaths
       wx.uploadFile({
         url: 'https://example.weixin.qq.com/upload', //开发者服务器地址
         filePath: tempFilePaths[0], // 要上传的资源的路径
         name: 'file', // 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
         formData: {
           'user': 'test'
         }, // HTTP 请求中其他额外的 form data
         success (res){
           const data = res.data // 开发者服务器返回的数据
         }
       })
     }
    })```
    
    

 

后端代码

项目采用SpringCloud,会经过一个前置模块进行远程调用,用到Feign(这个需要特别注意!)

  • 前置模块(调用模块)

    @PostMapping("file/uploadFile")
    @ApiOperation(value = "上传文件", notes = "上传文件")
    public ApiResponse uploadFiles(HttpServletRequest request, @RequestParam(value = "file", required = false) MultipartFile file){
        return feignBusinessService.uploadFiles(request,file);
    }
    
  • FeignService

    openfeign默认不支持文件参数,但提供了feign-form扩展工具。
    引入 io.github.openfeign.form:feign-form:3.8.0io.github.openfeign.form:feign-form-spring:3.8.0 maven依赖,注入 SpringFormEncoder ,在 @FeignClient 中配下configuration即可。
     

    Maven依赖

        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form-spring</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>10.7.4</version>
            <scope>compile</scope>
        </dependency>
    

    配置类

    public class FeignMultipartSupportConfig {
    
     @Autowired
     private ObjectFactory<HttpMessageConverters> messageConverters;
    
     @Bean
     public Encoder feignFormEncoder() {
         return new SpringFormEncoder(new SpringEncoder(messageConverters));
     }
    }
    

    接口编写

    • @FeignClient使用配置类
    • @PostMapping设置 consumes = MediaType.MULTIPART_FORM_DATA_VALUE
    • 使用@RequestPart(),不能使用@RequestParam()
    @Component
    @FeignClient(name = "businessApi",configuration= FeignMultipartSupportConfig.class)
    public interface FeignBusinessService {
     /**
      * 上传文件
      * 也可以使用MultipartFile[]上传多个文件
      * @param request
      * @param file
      * @return
      */
     @PostMapping(value = "app/file/uploadFile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     ApiResponse uploadFiles(@RequestParam("request") HttpServletRequest request, @RequestPart("file") MultipartFile file);
    }
    
  • 业务模块(被调用模块)

     /**
      * 上传文件
      *
      * @param request
      * @param file
      * @return
      * @throws IOException
      */
     @PostMapping("file/uploadFile")
     @ApiOperation(value = "上传文件", notes = "上传文件")
     public ApiResponse uploadFiles(HttpServletRequest request, @RequestParam(value = "file", required = false) MultipartFile file) throws IOException {
    
         request.setCharacterEncoding("UTF-8");
         log.info("执行图片上传");
         if (!file.isEmpty()) {
             log.info("成功获取照片");
             String fileName = file.getOriginalFilename();
             String path;
             String type;
             type = fileName.indexOf(".") != -1 ? fileName.substring(fileName.lastIndexOf(".") + 1) : null;
             log.info("图片初始名称为:" + fileName + " 类型为:" + type);
             if (type != null) {
                 if ("GIF".equals(type.toUpperCase()) || "PNG".equals(type.toUpperCase()) || "JPG".equals(type.toUpperCase())) {
                       // 上传到本地
    //                    // 项目在容器中实际发布运行的根路径
    //                    String realPath = request.getSession().getServletContext().getRealPath("/");
    //                    // 自定义的文件名称
    //                    String trueFileName = System.currentTimeMillis() + fileName;
    //                    // 设置存放图片文件的路径
    //                    path = realPath + "/uploads/" + trueFileName;
    //                    log.info("存放图片文件的路径:" + path);
    //                    File path1 = new File(path);
    //                    if (!path1.exists()) {
    //                        path1.mkdirs();
    //                    }
    //                    file.transferTo(path1);
    //                    log.info("文件成功上传到指定目录下");
    
                     // 上传到服务器
                     String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
                     String trueFileName = StringUtils.getSimpleNum() + suffix;
                     boolean flag = ftpUtil.uploadByBytes(remoteWay, file.getBytes(), trueFileName);
                     if (!flag) {
                         return ApiResponse.getApiResponse("添加失败");
                     }
                     return ApiResponse.getApiResponse(ftpUtil.getLookPath(remoteWay + "/" + trueFileName)); // 返回服务器返回的图片地址
                 } else {
                     log.info("不是我们想要的文件类型,请按要求重新上传");
                     return ApiResponse.getFailApiResponse();
                 }
             } else {
                 log.info("文件类型为空");
                 return ApiResponse.getFailApiResponse();
             }
         } else {
             log.info("没有找到相对应的文件");
             return ApiResponse.getFailApiResponse();
         }
     }
    

    FTP工具类

    @Slf4j
    @Component
    public class FileFtpUtil {
    /**
      * ftp上传单个文件
      *
      * @param path          上传至ftp的路径名不包括文件名
      * @param localFilePath 要上传的本地文件全路径名
      * @throws IOException
      */
     public boolean upload(String path, String localFilePath) {
    
         boolean result = false;
    
         //初始化ftp链接
         this.initFtpClient();
         //构建文件输入流
         FileInputStream fis = null;
    
         try {
             //处理上传目录不存在。上传前先构建一次目录,避免文件目录不存在报错
             ftp.makeDirectory(remote + path);
             // 切换上传目录
             if (this.changeWorkingDirectory(path)) {
                 File srcFile = new File(localFilePath);
                 if (srcFile.exists() && srcFile.isFile()) {
                     fis = new FileInputStream(srcFile);
                     result = ftp.storeFile(srcFile.getName(), fis);
                     if (result) {
                         log.info("FTP=============文件上传 目录:{}  文件名:{}  成功", path, srcFile.getName());
                     } else {
                         log.info("FTP=============文件上传 目录:{}  文件名:{}  失败", path, srcFile.getName());
                     }
                 }
             }
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try {
                 if (null != fis) {
                     fis.close();
                 }
                 //关闭ftp
                 this.close();
             } catch (IOException e) {
                 throw new RuntimeException("关闭FTP连接发生异常!", e);
             }
         }
         return result;
     }
     }
    

    配置文件

    ftp:
      ip: xxx // 服务器IP
      port: xxx
      user: xxx
      pwd: xxx
      #  文件服务器路径前缀
      remote: xxx
      #  文件服务器路径
      route-way: xxx
      #  文件服务器文件查看地址
      look-path: xxx
    

 

遇到的BUG

  • [Current request is not a multipart request] with root cause
    解决方案:检查Content-Type,设置为multipart/form-data。也有可能不是前端的问题,后台没有接收到参数。

  • nested exception is java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode

  • 添加对文件的配置后报错: feign.codec.EncodeException: class java.util.LinkedHashMap is not a type supported by this encoder.

    当时配置类如下:

    @Configuration
    public class FeignMultipartConfig {
    
     @Bean
     @Primary
     @Scope("prototype")
     public SpringFormEncoder multipartFormEncoder() {
         return new SpringFormEncoder();
     }
    
     @Bean
     public feign.Logger.Level multipartLoggerLevel() {
         return feign.Logger.Level.FULL;
     }
    }
    

    解决方案:将配置类改为

    public class FeignMultipartSupportConfig {
    
     @Autowired
     private ObjectFactory<HttpMessageConverters> messageConverters;
    
     @Bean
     public Encoder feignFormEncoder() {
         return new SpringFormEncoder(new SpringEncoder(messageConverters));
     }
    }
    

 
参考:

1.Feign上传文件的常见问题
2.微信小程序上传图片到服务器(java后台以及使用springmvc)

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 微信小程序开发是一种基于微信平台的应用程序开发方式,可以在微信内直接运行的应用程序。它可以实现类似于APP的功能,但相比APP更加轻量、快速、易于开发和使用。 微信小程序的开发主要分为前端和后端两部分。 前端开发是指通过使用小程序开发框架(如原生开发、wepy等)进行界面和交互的开发。开发者可以使用HTML、CSS和Javascript等技术进行整体的页面布局设计和交互逻辑的编写。通过小程序开发框架提供的API和组件,可以实现丰富的界面效果和功能。在前端开发中,可以通过调用后端接口获取数据或进行页面跳转等操作。 后端开发是指通过使用Java等编程语言进行服务器端的开发。在微信小程序中,后端开发主要用于数据的处理和管理。开发者可以通过后端开发来搭建服务器、编写API接口,实现数据存储和处理、权限控制、业务逻辑等功能。后端开发需要结合小程序前端的需求,定义数据的格式和访问方式,并与前端进行交互。 微信小程序开发前端和后端的配合是整个开发过程中的重要环节。开发者需要根据产品需求和设计稿进行界面和交互的开发,并将数据以适当的格式传输给后端进行处理和管理。前后端的协作可以通过API接口进行,前端调用后端提供的接口,传递参数并获取数据。开发者可以根据具体需求和开发框架的限制进行功能开发和调试,最终实现微信小程序的各项功能需求。 总之,微信小程序开发需要前端和后端的配合,前端负责界面和交互的开发,后端负责数据的处理和管理,两者相互合作,共同实现微信小程序的功能和效果。 ### 回答2: 微信小程序开发包括前端和后端两个主要部分。 1. 前端开发:微信小程序前端开发主要使用HTML、CSS和JavaScript等技术,通过编写小程序页面的HTML结构、样式和交互逻辑来实现小程序的界面和功能。开发者可以使用微信提供的开发者工具进行开发和调试,还可以利用第三方框架如Vue.js、React等来简化开发流程。 在前端开发中,开发者需要了解微信小程序的基本组件和API,以及小程序的生命周期、页面间的跳转和传递数据等。同时,还需要掌握微信小程序的开发规范和设计原则,以保证用户体验和小程序的可靠性。 2. 后端开发:微信小程序后端开发主要使用Java等编程语言进行实现。后端开发者需要负责处理小程序前端发送来的请求,验证用户身份,获取和处理数据,并将结果返回给前端。 在后端开发中,开发者需要使用Java开发框架如Spring Boot、Spring Cloud等,搭建服务器环境并实现业务逻辑。此外,还需要与数据库进行交互,操作和管理数据。同时,为了提高小程序的性能和可靠性,开发者还需要进行性能优化、错误处理和安全防护等工作。 综上所述,微信小程序开发需要前端和后端的配合合作。前端负责实现小程序的界面和用户交互,后端负责处理数据和业务逻辑。通过整合两者的能力,可以开发出功能完善、用户体验较好的微信小程序。 ### 回答3: 微信小程序是一种基于微信平台的应用程序开发模式,它具有轻量级、快速加载和便捷的特点。微信小程序开发涉及到前端和后端两方面的技术。 在前端开发中,我们需要掌握HTML、CSS和JavaScript等基础技术,同时需要熟悉微信小程序提供的开发框架和API。前端开发主要包括页面布局、样式设计、交互逻辑实现等工作。通过使用微信小程序的框架和API,我们可以快速地开发小程序,并且能够提供良好的用户体验。 在后端开发中,我们通常选择使用Java语言进行开发。Java是一种常用的编程语言,具有广泛的应用领域和稳定的性能。后端开发主要涉及到数据处理、业务逻辑编写、接口开发等方面的工作。我们可以使用Java的一些开发框架和工具,如SpringSpringBoot等,来进行后端开发。这些框架和工具提供了丰富的功能模块,可以帮助我们快速地构建小程序所需的后端服务。 总而言之,微信小程序的开发涉及到前端和后端两方面的技术。前端开发主要负责小程序的页面设计和交互逻辑实现,后端开发则负责提供数据处理和业务逻辑支持。通过前端和后端的协同工作,我们能够开发出功能完善、用户友好的微信小程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值