You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot+ReactJS的MySQL员工表中存储头像(非BLOB优先)

员工头像存储解决方案(Spring Boot + MySQL)

一、优先方案:文件存储+数据库保存访问路径

这是行业通用的最佳实践,避免直接在数据库存储二进制文件导致的性能问题,同时便于文件的管理和CDN加速。

1. 数据库表调整

给employees表新增avatar_url字段,用于存储头像文件的访问路径/文件名:

ALTER TABLE employees ADD COLUMN avatar_url VARCHAR(500) COMMENT '员工头像访问路径';

2. 修改Employee.java实体类

添加对应字段及相关方法:

package net.employee_crud.springboot.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name="employees")
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "last_name")
    private String lastName;
    
    @Column(name = "email_id")
    private String emailId;
    
    @Column(name = "department_name")
    private String department;
    
    // 新增头像路径字段
    @Column(name = "avatar_url")
    private String avatarUrl;
    
    public Employee() {
        
    }
    
    // 更新带头像路径的构造方法
    public Employee(String firstName, String lastName, String emailId, String department, String avatarUrl) {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.department = department;
        this.avatarUrl = avatarUrl;
    }
    
    // 原有getter/setter保持不变,新增以下方法
    public String getAvatarUrl() {
        return avatarUrl;
    }

    public void setAvatarUrl(String avatarUrl) {
        this.avatarUrl = avatarUrl;
    }
    
    // 其他原有方法...
}

3. 修改EmployeeController.java,支持头像上传

新增单独的头像上传接口,同时可调整创建/更新接口支持头像路径传入:

package net.employee_crud.springboot.controller;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import net.employee_crud.springboot.exception.ResourceNotFounudException;
import net.employee_crud.springboot.model.Employee;
import net.employee_crud.springboot.repository.EmployeeRepository;

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/v1/")
public class EmployeeController {
    
    @Autowired
    private EmployeeRepository employeeRepository;
    
    // 本地文件存储路径(可配置到application.properties)
    private static final String UPLOAD_DIR = "src/main/resources/static/avatars/";

    // 原有CRUD接口保持不变...
    
    // 新增:上传员工头像接口
    @PostMapping("/employees/{id}/avatar")
    public ResponseEntity<String> uploadAvatar(@PathVariable Long id, @RequestParam("file") MultipartFile file) {
        // 1. 校验员工是否存在
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFounudException("Employee Not exist with id: " + id));
        
        // 2. 校验文件类型和大小
        if (file.isEmpty() || !file.getContentType().startsWith("image/")) {
            return ResponseEntity.badRequest().body("请上传有效的图片文件");
        }
        
        // 3. 生成唯一文件名避免覆盖
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        File uploadPath = new File(UPLOAD_DIR);
        
        // 4. 创建存储目录(如果不存在)
        if (!uploadPath.exists()) {
            uploadPath.mkdirs();
        }
        
        try {
            // 5. 保存文件到本地
            file.transferTo(new File(UPLOAD_DIR + fileName));
            
            // 6. 更新数据库中的头像路径(这里用相对路径,前端可拼接访问地址)
            String avatarUrl = "/avatars/" + fileName;
            employee.setAvatarUrl(avatarUrl);
            employeeRepository.save(employee);
            
            return ResponseEntity.ok("头像上传成功,访问路径:" + avatarUrl);
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("头像上传失败:" + e.getMessage());
        }
    }
    
    // 可选:修改创建员工接口,支持传入头像路径
    @PostMapping("/employees")
    public Employee createEmployee(@RequestBody Employee employee) {
        return employeeRepository.save(employee);
    }
    
    // 可选:修改更新员工接口,支持更新头像路径
    @PutMapping("/employees/{id}")
    public ResponseEntity<Employee> updateEmployee(@PathVariable Long id,@RequestBody Employee employee_details){
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(()-> new ResourceNotFounudException("Employee Not exist with id: " + id));
        
        employee.setFirstName(employee_details.getFirstName());
        employee.setLastName(employee_details.getLastName());
        employee.setEmailId(employee_details.getEmailId());
        employee.setDepartment(employee_details.getDepartment());
        // 新增更新头像路径
        if (employee_details.getAvatarUrl() != null) {
            employee.setAvatarUrl(employee_details.getAvatarUrl());
        }
        
        Employee updated_Employee = employeeRepository.save(employee);
        return ResponseEntity.ok(updated_Employee);
    }
    
    // 其他原有接口...
}

4. 配置Spring Boot静态资源访问

如果使用本地存储,需要确保前端能访问到头像文件,可在application.properties中添加:

spring.web.resources.static-locations=classpath:/static/
spring.mvc.static-path-pattern=/**

二、备选方案:基于BLOB的数据库存储方案

仅当业务必须将头像存储在数据库时使用,此方案会增加数据库负担,不推荐大文件场景。

1. 数据库表调整

给employees表新增avatar字段,类型为LONGBLOB:

ALTER TABLE employees ADD COLUMN avatar LONGBLOB COMMENT '员工头像二进制数据';

2. 修改Employee.java实体类

添加二进制头像字段,使用@Lob注解标记:

package net.employee_crud.springboot.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;

@Entity
@Table(name="employees")
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "last_name")
    private String lastName;
    
    @Column(name = "email_id")
    private String emailId;
    
    @Column(name = "department_name")
    private String department;
    
    // 新增头像二进制字段
    @Lob
    @Column(name = "avatar")
    private byte[] avatar;
    
    public Employee() {
        
    }
    
    // 更新构造方法(可选,根据业务是否需要)
    public Employee(String firstName, String lastName, String emailId, String department, byte[] avatar) {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.department = department;
        this.avatar = avatar;
    }
    
    // 新增getter/setter
    public byte[] getAvatar() {
        return avatar;
    }

    public void setAvatar(byte[] avatar) {
        this.avatar = avatar;
    }
    
    // 其他原有方法...
}

3. 修改EmployeeController.java,支持BLOB头像上传与获取

package net.employee_crud.springboot.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import net.employee_crud.springboot.exception.ResourceNotFounudException;
import net.employee_crud.springboot.model.Employee;
import net.employee_crud.springboot.repository.EmployeeRepository;

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/v1/")
public class EmployeeController {
    
    @Autowired
    private EmployeeRepository employeeRepository;
    
    // 原有CRUD接口保持不变...
    
    // 新增:上传BLOB头像接口
    @PostMapping("/employees/{id}/avatar/blob")
    public ResponseEntity<String> uploadAvatarBlob(@PathVariable Long id, @RequestParam("file") MultipartFile file) {
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFounudException("Employee Not exist with id: " + id));
        
        if (file.isEmpty() || !file.getContentType().startsWith("image/")) {
            return ResponseEntity.badRequest().body("请上传有效的图片文件");
        }
        
        try {
            // 将文件转成字节数组存入数据库
            byte[] avatarBytes = file.getBytes();
            employee.setAvatar(avatarBytes);
            employeeRepository.save(employee);
            
            return ResponseEntity.ok("头像上传成功");
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("头像上传失败:" + e.getMessage());
        }
    }
    
    // 新增:获取BLOB头像接口
    @GetMapping("/employees/{id}/avatar/blob")
    public ResponseEntity<byte[]> getAvatarBlob(@PathVariable Long id) {
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFounudException("Employee Not exist with id: " + id));
        
        if (employee.getAvatar() == null) {
            return ResponseEntity.noContent().build();
        }
        
        // 设置响应头,指定图片类型
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG); // 可根据实际文件类型调整
        
        return new ResponseEntity<>(employee.getAvatar(), headers, HttpStatus.OK);
    }
    
    // 其他原有接口...
}

内容的提问来源于stack exchange,提问作者Rishabh Teli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:47:05