草庐IT

vue element-ui+springboot 的图片上传及展示

nefu__lian 2023-08-23 原文

文章目录

问题

搜索了很多 图片上传的方式 ,但只看到单一的图片的上传方案,
但是我需要将图片和表单中其他数据 ,如 名称,描述 等一起 保存到数据库

该项目为 本地项目,前后端分离 ,前端8080 端口,后端 8081端口

1. 效果

思路:
1. 首先图片上传 调用 upload方法 ,后端处理后 将图片 url 返回给前端
2. 前端将 后端返回的url 图片 赋值 给 表单中的对应字段
3. 将全部的表单数据 保存数据库中

以表单形式上传至后端,将表单信息 (包括图片url)保存到数据库

图片展示效果

2. 前端代码

只给出主要的代码,当 新增表单信息时 通过 el-upload 组件进行图片上传,
action 中为向后端发起请求路径,当上传成功 :on-success=“handleAvatarSuccess” ,调用handleAvatarSuccess方法,
将后端返回的图片的url 地址 赋值 给editForm.img 属性, 点击确定会调用 submitForm(‘editForm’) 方法,将 表单信息发送到后端, 在全部存储到数据库

<el-dialog
        title="虫害信息"
        :visible.sync="dialogVisible"
        width="1500px"
        :before-close="handleClose">

      <el-form :model="editForm" :rules="editFormRules" ref="editForm">
        <el-form-item label="虫害名称" prop="title" label-width="120px">
          <el-input v-model="editForm.title" autocomplete="off"></el-input>
        </el-form-item>


        <el-form-item label="虫害信息"  prop="message" label-width="120px"  >
          <el-input type="textarea" v-model="editForm.message" autocomplete="off" :rows="20" style="font-size:20px"></el-input>
        </el-form-item>

        <el-form-item label="图片上传"  prop="img" label-width="120px">
          <el-upload
              class="upload-demo"
              action="http://localhost:8081/sys/express/upload"
              :on-preview="handlePreview"
              :on-remove="handleRemove"
              :before-remove="beforeRemove"
              :on-success="handleAvatarSuccess"
              :limit="1"
              :on-exceed="handleExceed"
              :file-list="fileList">
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
        </el-form-item>

        <el-form-item label="发布人"  prop="username" label-width="120px">
          <el-input v-model="editForm.username" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="resetForm('editForm')">取 消</el-button>
        <el-button type="primary" @click="submitForm('editForm')">确定</el-button>
      </div>

    </el-dialog>

methods:{

submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log(this.editForm.img)
          this.$axios.post('/sys/pest/'+(this.editForm.id?'update':'save'),this.editForm)
              .then(res=>{
                // 消息框提示操作成功
                this.$message({
                  showClose: true,
                  message: '恭喜你,操作成功',
                  type: 'success',
                  //关闭时的回调函数, 参数为被关闭的 message 实例
                  onClose:()=>{
                    this.getPestList()
                  }
                })
              })
          this.resetForm('editForm')
          this.dialogVisible=false;
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
     handleRemove(file, fileList) {
      console.log(file, fileList);
    },
    handlePreview(file) {
      window.open(file.response.url)
      console.log(file);
    },
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    },
    beforeRemove(file, fileList) {
      return this.$confirm(`确定移除 ${ file.name }?`);
    },
    handleAvatarSuccess(res, file) {
      this.editForm.img = res.url
    }
}

展示界面 (主要展示 后端传来的 数据,以表单形式展示)

<el-dialog
        title="虫害信息详情"
        :visible.sync="expressDialogVisible"
        width="1500px">

      <el-form :model="expressForm" :rules="expressFormRules" ref="expressForm">
        <el-form-item label="虫害名称" prop="title" label-width="120px">
          <el-input v-model="expressForm.title" autocomplete="off"></el-input>
          <!--          <el-alert-->
          <!--              title="初始密码为888888"-->
          <!--              :closable="false"-->
          <!--              type="info"-->
          <!--              style="line-height: 12px;"-->
          <!--          ></el-alert>-->
        </el-form-item>
        <el-form-item label="虫害信息"  prop="message" label-width="120px"  >
          <el-input type="textarea" v-model="expressForm.message" autocomplete="off" :rows="20" style="font-size:20px"></el-input>
        </el-form-item>
        <el-form-item label="虫害图片"  prop="img" label-width="120px"  v-if="expressForm.img!=null" >
          <el-image
              v-model="expressForm.img"
              :src="expressForm.img"
             ></el-image>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <!--        <el-button @click="resetForm('editForm')">取 消</el-button>-->
        <el-button type="primary" @click="cancalexpressForm('expressForm')">关闭</el-button>
      </div>


    </el-dialog>

3. 后端代码

当前端通过 el-upload 上传图片, 根据请求路径 由@RequestMapping 匹配到 fileupload 方法,
filePath 为本地项目 resource 目录的地址 ,UUID 处理图片名称,变为唯一名称生成url 后 返回给前端,前端完成 url 值赋值 到表单。

之后前端再 提交表单数据 到后端 ,由PestController 处理后, 保存到数据库中

@RestController
@RequestMapping("/sys/express")
public class ExpressInfoController extends BaseController {

    @PostMapping("/upload")
    public Map<String,Object> fileupload(MultipartFile file, HttpServletRequest req) {
        Map<String, Object> result = new HashMap<>();

        // 放在本地项目 目录
        String filePath="D:\\idea-workspace\\vueadmin-back\\src\\main\\resources\\static\\img";
        File folder = new File(filePath);

        if (!folder.exists()) {
            folder.mkdirs();
        }
        // 生成新的文件名
        String oldName = file.getOriginalFilename();
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
        // System.out.println(oldName);
        //System.out.println(newName);
        try {
            // 保存文件到指定路径
            file.transferTo(new File(folder, newName));
            String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort()+"/img/"  + newName;

            System.out.println(url);
            result.put("status", "OK");
            result.put("name", oldName);
            result.put("url", url);

        } catch (IOException e) {
            result.put("status", "ERROR");
            result.put("msg", e.getMessage());
        }
        return result;
    }

}
@RestController
@RequestMapping("/sys/pest")
public class PestController extends BaseController {

    @PostMapping("/save")
    public Result save(@RequestBody ExpressInfo expressInfo){
        expressInfo.setCreated(LocalDateTime.now());
        expressInfo.setUpdated(LocalDateTime.now());
        expressInfo.setStatu(Const.STATUS_ON);
        expressInfoService.save(expressInfo);
        return Result.success(expressInfo);
    }

    @PostMapping("/update")
    public Result update(@RequestBody ExpressInfo expressInfo){

        expressInfo.setUpdated(LocalDateTime.now());
        expressInfoService.updateById(expressInfo);

        return Result.success(expressInfo);
    }

}

4. 数据库表

CREATE TABLE `express_info` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `type` int DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  `message` varchar(10000) DEFAULT NULL,
  `img` varchar(100) DEFAULT NULL,
  `username` varchar(100) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  `statu` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

5. 其他注意事项

  1. 前后端 分离 ,请求的跨域处理
  2. 图片url 保存到数据库,图片实际保存在本地项目的 目录下, 注意开启静态资源的访问权限 (拦截器中设置,或者 我是在spring security 中 设置的请求白名单)
  3. 添加图片上传后,发现回显不了,404,发现网站上也不显示图片,查看数据库、存储路径都是正确的,在重启服务器后照片又显示了。
    问题原因:
    由于spring启动后会将项目资源打包,但我们在运行中添加的照片并不会放在打包的资源里面,所以访问不到图片,而在重新启动项目后,又重新将资源打包,其中就包含了新加入的照片,所以可以访问。
    配置虚拟路径访问后,就直接读取的本地的照片,所以可以显现出来了
// 问题2 配置白名单
package com.ljw.config;

@Configuration
@EnableWebSecurity     // 开启Security 的安全策略
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 在post 请求前进行权限校验
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    LoginFailureHandler loginFailureHandler;
    @Autowired
    LoginSuccessHandler loginSuccessHandler;
    @Autowired
    CaptchaFilter captchaFilter;

    @Bean
    JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        JwtAuthenticationFilter jwtAuthenticationFilter
                 = new JwtAuthenticationFilter(authenticationManager());
        return jwtAuthenticationFilter;
    }

    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    UserDetailServiceImpl userDetailService;

    @Autowired
    JwtLogoutSuccessHander jwtLogoutSuccessHander;


    // 请求白名单
    private  static  final  String[] URL_WHILELIST={
      "/login","/logout",
      "/captcha","/favicon.ico","/test/**","/sys/express/upload",
       "/img/**","/static/**"
    };

    protected void configure(HttpSecurity http) throws Exception {

       http.cors().and().csrf().disable()
               // 登录配置
        .formLogin()
                             // 登录成功或者失败后,对应进行回调
               .successHandler(loginSuccessHandler)
               .failureHandler(loginFailureHandler)

               // 退出登录 配置
         .and()
               .logout()
               .logoutSuccessHandler(jwtLogoutSuccessHander)

              // 禁用session
         .and()
                              //设置无状态的连接,即不创建session
               .sessionManagement()
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
             // 配置拦截规则
         .and()
                              // 除了 白名单的请求 放过,其他正常拦截
               .authorizeRequests()
               .antMatchers(URL_WHILELIST).permitAll()
               .anyRequest().authenticated()
             // 异常处理器
         .and()
               .exceptionHandling()
               .authenticationEntryPoint(jwtAuthenticationEntryPoint)       // 认证失败 异常处理入口
               .accessDeniedHandler(jwtAccessDeniedHandler)            // 配置 权限不足 处理器

             // 配置自定义的过滤器
          .and()
               .addFilter(jwtAuthenticationFilter())
               .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)  // 登录验证码过滤器

        ;
    }


    /**
     * 配置
     * 将 userDetailService的实现类 注入到 security 中
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }
}



//  问题1 跨域
// 问题3 虚拟路径配置   addResourceHandlers()
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addExposedHeader("Authorization");
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
//          .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }


// 图片访问 虚拟路径配置 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/img/**")
                .addResourceLocations("file:D:\\idea-workspace\\vueadmin-back\\src\\main\\resources\\static\\img\\");
    }
}

有关vue element-ui+springboot 的图片上传及展示的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  3. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  4. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  5. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  6. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  7. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  8. ruby-on-rails - 安全地显示使用回形针 gem 上传的图像 - 2

    默认情况下:回形针gem将所有附件存储在公共(public)目录中。出于安全原因,我不想将附件存储在公共(public)目录中,所以我将它们保存在应用程序根目录的uploads目录中:classPost我没有指定url选项,因为我不希望每个图像附件都有一个url。如果指定了url:那么拥有该url的任何人都可以访问该图像。这是不安全的。在user#show页面中:我想实际显示图像。如果我使用所有回形针默认设置,那么我可以这样做,因为图像将在公共(public)目录中并且图像将具有一个url:Someimage:看来,如果我将图像附件保存在公共(public)目录之外并且不指定url(同

  9. ruby-on-rails - Rails 3,在RAILS_ROOT上方显示来自本地文件系统的jpg图片 - 2

    我正在尝试找出一种方法来显示来自不在RAILS_ROOT下(在RedHat或Ubuntu环境中)的已安装文件系统的图像。我不想使用符号链接(symboliclink),因为这个应用程序实际上是通过Tomcat部署的,而当我关闭Tomcat时,Tomcat会尝试跟随符号链接(symboliclink)并删除挂载中的所有图像。由于这些文件的数量和大小,将图像放在public/images下也不是一种选择。我查看了send_file,但它只会显示一张图片。我需要在一个格式良好的页面中显示6个请求的图像。由于膨胀,我宁愿不使用Base64编码,但我不知道如何将图像数据与呈现的页面一起传递下去。

  10. ruby - 使用法拉第上传文件 - 2

    我在尝试使用Faraday将文件上传到网络服务时遇到问题。我的代码:conn=Faraday.new('http://myapi')do|f|f.request:multipartendpayload={:file=>Faraday::UploadIO.new('...','image/jpeg')}conn.post('/',payload)尝试发布后似乎没有任何反应。当我检查响应时this是我所看到的:#:post,:body=>#,#,@opts={}>,#],@index=0>>,#>],@ios=[#,#,@opts={}>,#],@index=0>,#],@index=0>

随机推荐