springdata+fastdfs实现文件上传到服务器

1、首先需要安装fastdfs,请自行参考

使用docker搭建FastDFS文件系统

装好后启动,因为服务器比较low,所以我这里只把后端和mysql放到了服务器上,前端放在了本地
在这里插入图片描述

2、后端

(1)、配置application.yml

server:
  port: 8080
spring:
  devtools:
    restart:
      enabled: false
  datasource:
    url: jdbc:mysql://39.106.193.224:3306/Good?useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
itcast-fastdfs:
  #文件上传临时目录
  upload_location: ${user.dir}/multipartUpload

(2)、fastfds配置文件

## fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80

fastdfs.tracker_servers = 39.106.193.224:22122

(3)、pojo

因为是两表,所以这里用了双向一对一

@Entity
@Table(name = "goods")
public class Goods {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "goodsid")
    private int goodsId;
    @Column(name = "goodsname")
    private String goodsName;
    @Column(name = "goodsprice")
    private int goodsPrice;
    @Column(name = "imageurl",length = 255)
    private String imageUrl;
    @Column(name = "status")
    private int status;
    @Column(name = "goodssp")
    private String goodsSp;

    @OneToOne(mappedBy = "goods",cascade = CascadeType.ALL)
    private GoodsDetail goodsDetail;

    public int getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(int goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public int getGoodsPrice() {
        return goodsPrice;
    }

    public void setGoodsPrice(int goodsPrice) {
        this.goodsPrice = goodsPrice;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getGoodsSp() {
        return goodsSp;
    }

    public void setGoodsSp(String goodsSp) {
        this.goodsSp = goodsSp;
    }

    public GoodsDetail getGoodsDetail() {
        return goodsDetail;
    }

    public void setGoodsDetail(GoodsDetail goodsDetail) {
        this.goodsDetail = goodsDetail;
    }
}
@Entity
@Table(name = "goodsdetails")
public class GoodsDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "goodsdetailid")
    private int goodsdetailId;
    @Column(name = "goodtye")
    private String goodTye;

//    @Column(name = "goodsid")
//    private int goodsId;
    @JsonIgnore
    @OneToOne(fetch = FetchType.EAGER,optional = false)
    @JoinColumn(name="goodsid", referencedColumnName = "goodsid",unique = true )
    private Goods goods;

    public int getGoodsdetailId() {
        return goodsdetailId;
    }

    public void setGoodsdetailId(int goodsdetailId) {
        this.goodsdetailId = goodsdetailId;
    }

    public String getGoodTye() {
        return goodTye;
    }

    public void setGoodTye(String goodTye) {
        this.goodTye = goodTye;
    }

    public Goods getGoods() {
        return goods;
    }

    public void setGoods(Goods goods) {
        this.goods = goods;
    }
}

(4)、service
dao层省略,没什么东西

@Service
@Transactional
public class GoodsService {
    @Resource
    private GoodsDao goodsDao;

    public List<Goods> findAll() {
        List<Goods> goodsList = goodsDao.findAll();
        return goodsList;
    }
    public void  delGoods(int id){
        goodsDao.deleteById(id);
    }
    public Goods saveGoods(Goods goods){
        goods.getGoodsDetail().setGoods(goods);
        return goodsDao.save(goods);
    }
    public void updGoods(Goods goods){
        goods.getGoodsDetail().setGoods(goods);
        goodsDao.saveAndFlush(goods);
    }
    public void upGood(int id){
        goodsDao.updGoodsStatus(id);
    }
    public void downGood(int id){
        goodsDao.updGoodsStatus2(id);
    }
}
@Service
@Transactional
public class GoodsDetailService {
    @Resource
    private GoodsDatailDao goodsDatailDao;
    public List<GoodsDetail> findAll(){
        return goodsDatailDao.findAll();
    }
    public void  delGoods(int id){
        goodsDatailDao.deleteById(id);
    }
    public void saveGoods(GoodsDetail goodsDetail){
        goodsDatailDao.save(goodsDetail);
    }
    public void updGoods(GoodsDetail goodsDetail){
        goodsDatailDao.saveAndFlush(goodsDetail);
    }
}

(5)、controller
ResponseResult 是一个工具类,不用也没关系

@Controller
public class GoodsController {
    @Resource
    private GoodsService goodsService;
    @GetMapping("findGoods")
    @ResponseBody
    public List<Goods> findGoods(){
        return goodsService.findAll();
    }
    @DeleteMapping("delGoods/{goodsId}")
    @ResponseBody
    public ResponseResult delGoods(@PathVariable("goodsId") int id){
        goodsService.delGoods(id);
        ResponseResult result = new ResponseResult();
        return result;
    }

    @PostMapping("saveGoods")
    @ResponseBody
    public ResponseResult saveGoods(@RequestBody Goods goods) {
        Goods goods1 = goodsService.saveGoods(goods);
        ResponseResult result = new ResponseResult();
        return result;
    }
    @PutMapping("modifyGoods")
    @ResponseBody
    public ResponseResult modifyGoods(@RequestBody Goods goods) {
        goodsService.updGoods(goods);
        ResponseResult result = new ResponseResult();
        return result;
    }

    @PutMapping("upGoods/{goodsId}")
    @ResponseBody
    public ResponseResult upGoods(@PathVariable("goodsId") int id){
        goodsService.upGood(id);
        ResponseResult result = new ResponseResult();
        return result;
    }

    @PutMapping("downGoods/{goodsId}")
    @ResponseBody
    public ResponseResult downGoods(@PathVariable("goodsId") int id){
        goodsService.downGood(id);
        ResponseResult result = new ResponseResult();
        return result;
    }
}

文件上传controller

@RestController
@RequestMapping("/filesystem")
public class FileServerController {
    @Value("${itcast-fastdfs.upload_location}")
    private String upload_location;

    @PostMapping("/upload")
    public FileSystem upload(@RequestParam("file") MultipartFile file) throws IOException {
        //将文件先存储在web服务器上(本机),再调用fastDFS的client将文件上传到 fastDSF服务器
        FileSystem fileSystem = new FileSystem();
        //得到 文件的原始名称
        String originalFilename = file.getOriginalFilename();
        //扩展名
        String extention = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileNameNew = UUID.randomUUID()+extention;
        //定义file,使用file存储上传的文件
        File file1 = new File(upload_location+fileNameNew);
        file.transferTo(file1);
        //获取新上传文件的物理路径
        String newFilePath = file1.getAbsolutePath();
        try {
            //加载fastDFS客户端的配置 文件
            ClientGlobal.initByProperties("config/application-fastdfs.properties");
            System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
            System.out.println("charset=" + ClientGlobal.g_charset);

            //创建tracker的客户端
            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;
            //定义storage的客户端
            StorageClient1 client = new StorageClient1(trackerServer, storageServer);
            //文件元信息
            NameValuePair[] metaList = new NameValuePair[1];
            metaList[0] = new NameValuePair("fileName", originalFilename);
            //执行上传,将上传成功的存放在web服务器(本机)上的文件上传到 fastDFS
            String fileId = client.upload_file1(newFilePath,null, metaList);
            System.out.println("upload success. file id is: " + fileId);
            fileSystem.setFileId(fileId);
            fileSystem.setFilePath(fileId);
            fileSystem.setFileName(originalFilename);

            //通过调用service及dao将文件的路径存储到数据库中
            //...

            //关闭trackerServer的连接
            trackerServer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return fileSystem;
    }
}

public class FileSystem {
    private String fileId;

    private String filePath;

    private long fileSize;

    private String fileName;

    private String fileType;

    public String getFileId() {
        return fileId;
    }

    public String getFilePath() {
        return filePath;
    }

    public long getFileSize() {
        return fileSize;
    }

    public String getFileName() {
        return fileName;
    }

    public String getFileType() {
        return fileType;
    }

    public void setFileId(String fileId) {
        this.fileId = fileId;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public void setFileSize(long fileSize) {
        this.fileSize = fileSize;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }
}

后台到这就差不多了,这时候还获取不到图片路径,在能被项目加载到的配置类中加入以下代码,我放在了跨域的类中

@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("/app/tmp");
return factory.createMultipartConfig();
}

3、前端

<template>
  <div>
    <div class="bookstable">
      <el-row class="bookssavebtn">
        <el-button type="primary" @click="handleSave()" icon="el-icon-plus">新增</el-button>
      </el-row>
      <el-table :data="tableData" style="width: 100%" max-height="600px">
        <el-table-column v-show="showId" fixed prop="goodsId" label="编号" width="150"></el-table-column>
        <el-table-column prop="imageUrl" label="商品图片" width="250">
          <!-- 图片的显示 -->
          <template   slot-scope="scope">
            <img :src="scope.row.imageUrl"  min-width="70" height="90" />
          </template>
        </el-table-column>
        <el-table-column prop="goodsName" label="商品名称" width="150"></el-table-column>
        <el-table-column prop="goodsDetail.goodTye" label="型号" width="120"></el-table-column>
        <el-table-column prop="goodsPrice" label="价格" width="180"></el-table-column>
        <el-table-column prop="goodsSp" label="商铺" width="120"></el-table-column>
        <el-table-column label="是否上下架" prop="status" :formatter="stateFormat"></el-table-column>
        <el-table-column fixed="right" label="操作" width="150">
          <template slot-scope="scope">
            <el-button @click="handleStatusUp(scope.row.goodsId)" type="text" size="small" v-if="scope.row.status==2">
              上架
            </el-button>
            <el-button @click="handleStatusDown(scope.row.goodsId)" type="text" size="small" v-if="scope.row.status==1">
              下架
            </el-button>
            <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button>
            <!-- scope.row表示选中当前行的数据 -->
            <el-button type="text" @click="handleDelete(scope.row.goodsId)" size="small">删除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 编辑模块 dialog 组件  @open="dialogOpened"-->
      <el-dialog title="编辑信息" :visible.sync="dialogFormVisible" :before-close="closeDialog" center>
        <el-radio-group v-model="labelPosition" size="small">
          <!-- ref="books"绑定数据的显示集合  -->
          <el-radio-button label="left">左对齐</el-radio-button>
          <el-radio-button label="right">右对齐</el-radio-button>
          <el-radio-button label="top">顶部对齐</el-radio-button>
        </el-radio-group>
        <div style="margin: 20px;"></div>
        <el-form :label-position="labelPosition" label-width="80px" :model="goods" :rules="rules" ref="goods">
          <!-- 上面的:model绑定的是你的实体对象,:rules绑定的是你在data中设定的非空验证条件, ref="books"也是实体对象 -->
          <!-- 这里的prop绑定的是你实体对象里的属性,不需要实体对象点出来,直接写属性 -->
          <!-- 如果是数字类型的数据,使用v-model.number绑定,有利于文本类型判断 -->
          <el-form-item label="编号" prop="goodsId" v-show="showId">
            <el-input v-model="goods.goodsId" readonly></el-input>
          </el-form-item>
          <el-form-item label="商品图片" prop="imageUrl">

            <el-upload
              class="upload-demo"
              action="http://39.106.193.224:8080/filesystem/upload"
              :on-preview="handlePreview"
              :on-remove="handleRemove"
              :file-list="fileList"
              :on-success="getImageUrl"
              list-type="picture">
              <el-button size="small" type="primary" >点击上传</el-button>
              <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
            </el-upload>
            <!--&lt;!&ndash; 图片的显示 &ndash;&gt;-->
            <!--<template   slot-scope="scope">-->
              <!--<img :src="goods.imageUrl"  min-width="70" height="70" />-->
            <!--</template>-->
          </el-form-item>
          <el-form-item label="型号" prop="goodTye">
            <el-input v-model="goods.goodsDetail.goodTye"></el-input>
          </el-form-item>
          <el-form-item label="商品名称" prop="goodsName">
            <el-input v-model="goods.goodsName"></el-input>
          </el-form-item>
          <el-form-item label="价格" prop="goodsPrice">
            <el-input v-model.number="goods.goodsPrice"></el-input>
          </el-form-item>
          <el-form-item label="商铺" prop="goodsSp">
            <el-input v-model="goods.goodsSp"></el-input>
          </el-form-item>
          <el-form-item label="是否上下架" prop="status">
            <el-select v-model="goods.status" placeholder="请选择">
              <el-option
                v-for="item in status"
                :key="item.value"
                :label="item.label"
                :value="item.value">
              </el-option>
            </el-select>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <!-- 这里onSubmit('books'),books是你定义的实体对象 -->
          <el-button @click="onCancel('goods')">取 消</el-button>
          <el-button type="primary" @click="onSubmit('goods')">确 定</el-button>
        </div>
      </el-dialog>
    </div>
  </div>
</template>
<script>
  const axios = require('axios')
  export default {
    name: 'Goods',
    data () {
      return {
        fileList: [],
        tableData: [],//页面显示绑定对象
        dialogFormVisible: false,//编辑框显示隐藏
        labelPosition: 'right',//编辑框对齐方式
        showId: false,//设置编号隐藏或显示
        readonly: true,//设置编号只读
        status: [{
          value: 1,
          label: '上架'
        }, {
          value: 2,
          label: '下架'
        }],
        goods: {//编辑框实体对象
          goodsId: '',
          goodsName: '',
          goodsPrice: '',
          imageUrl: '',
          status: '',
          goodsSp: '',
          goodsDetail: {
            goodTye: '',
            goodsdetailId: ''
          }
        },
        // 表单验证规则
        rules: {
          goodsName: [{
            required: true,
            message: '请输入商品名称',
            trigger: 'blur'
          },
            {
              min: 0,
              max: 100,
              message: '长度大于0个字符',
              trigger: 'blur'
            }
          ],
          goodsSp: [{
            required: true,
            message: '请输入商铺',
            trigger: 'blur'
          }, {
            min: 0,
            max: 100,
            message: '长度大于0个字符',
            trigger: 'blur'
          }],
          status: [{
            required: true,
            message: '请选择状态',
            trigger: 'blur'
          }],
          goodsPrice: [{
            required: true,
            message: '请输入商品价格',
            trigger: 'blur'
          }]
        },
      }
    },
    created () {//创建加载事件
      var app = this
      console.log('init')
      this.init()
    },
    watch: {//监控一个值的变换

    }, methods: {//提供存放方法的地方
      handleRemove (file, fileList) {
        console.log(file, fileList)
      },
      handlePreview (file) {
        console.log(file)
      },
      //新增按钮事件
      handleSave () {
        this.showId = false//隐藏图书编号
        this.dialogFormVisible = true//显示编辑框
        this.goods = {//先将编辑框置空
          goodsId: '',
          goodsName: '',
          goodsPrice: '',
          imageUrl: '',
          status: '',
          goodsSp: '',
          goodsDetail: {
            goodTye: '',
            goodsdetailId: ''
          }
        }
      },
      //修改按钮事件
      handleEdit (row) {
        this.showId = true
        this.dialogFormVisible = true
        this.goods = row
      },
      handleStatusUp (id) {
        var vm = this
        this.$confirm('确认上架吗?').then(_ => {
          axios.put('/upGoods/' + id)
            .then(function (response) {
              vm.$message.success('上架成功')
              vm.init(vm) //刷新数据
            })
            .catch(function (error) {
            })
        })
          .catch(_ => {
            this.$notify({
              message: '上架操作已取消',
              type: 'info',
              duration: 3000
            })
          })
      },
      getImageUrl(file){
        this.goods.imageUrl="http://39.106.193.224:8888/"+file.fileId;
        console.log(this.goods.imageUrl)
      },
      stateFormat (row, column) {
        if (row.status === 1) {
          return '上架'
        } else if (row.status === 2) {
          return '下架'
        }
      },
      handleStatusDown (id) {
        var vm = this
        this.$confirm('确认下架吗?').then(_ => {
          axios.put('/downGoods/' + id)
            .then(function (response) {
              vm.$message.success('下架成功')
              vm.init(vm) //刷新数据
            })
            .catch(function (error) {
            })
        })
          .catch(_ => {
            console.log(_)
            this.$notify({
              message: '下架操作已取消',
              type: 'info',
              duration: 3000
            })
          })
      }
    ,
    //编辑提交事件
    onSubmit (name) {
      var id = this.goods.goodsId
      var vm = this
      this.$refs[name].validate(valid => {//用于表单验证
        if (valid) {//验证通过
          if (id == '') {
            console.log('-------新增-------')
            axios.post('/saveGoods/', this.goods)
              .then(function (response) {
                vm.$notify({
                  title: '提示',
                  message: '添加成功',
                  duration: 3000
                })
                // 重新加载数据;
                vm.init(vm)
              })
              .catch(function (error) {
                console.log(error)
              })
          } else {
            console.log('-------修改-------')
            axios
              .put('/modifyGoods/', this.goods)
              .then(function (response) {
                vm.$notify({
                  message: '编辑成功',
                  type: 'success',
                  duration: 3000
                })
                this.tableData = response.data
              })
              .catch(function (error) {
                console.log(error)
              })
          }
          vm.$message.success('提交成功!')
          this.dialogFormVisible = false
        } else {
          vm.$message.error('请完成必填项')
          this.$notify({
            message: '操作失败',
            type: 'error',
            duration: 3000
          })
        }
      })
    },
    //取消编辑框
    onCancel (formName) {
      this.$refs[formName].resetFields()//使关闭前的非空验证,错误提示清空
      this.dialogFormVisible = false
      this.$notify({
        message: '编辑框已关闭',
        type: 'info',
        duration: 3000
      })
    },
    closeDialog (done) {//编辑框右上角x,由于非空判断,清空问题而写
      done()//关闭窗口
      this.$refs.goods.clearValidate()
      this.$notify({
        message: '编辑框已关闭',
        type: 'info',
        duration: 3000
      })

    },
    init (h) {
      var app = this
      var a = h == undefined ? app : h
      console.log('init')
      axios.get('/findGoods',)
        .then(response => {
          // handle success
          console.log('============', response)
          a.tableData = response.data
          console.log('response', response)
        })
        .catch(function (error) {
          // handle error
          console.log(error)
        })
    },
    handleDelete (i) {//i为当前行的id
      var vm = this
      this.$confirm('确认删除吗?').then(_ => {
        axios.delete('/delGoods/' + i)
          .then(function (response) {
            vm.$message.success('删除成功')
            vm.init(vm) //刷新数据
          })
          .catch(function (error) {
          })
      })
        .catch(_ => {
          this.$notify({
            message: '删除操作已取消',
            type: 'info',
            duration: 3000
          })
        })
    },
  }
  ,
  }

</script>
<style>
  .bookstable {
    margin: 0 auto;
    width: 60%;
    position: relative;
  }

  .bookssavebtn {
    height: 50px;
    float: left;
  }

</style>

建好数据库,把那些端口改成自己的一个应该就能运行了
把项目打包到服务器上,然后java -jar jar包就OK了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值