Vue+SpringBoot to upload user avatars (with front-end source code)

Posted by sh0tgun on Tue, 21 Dec 2021 01:25:17 +0100

1, Background

  • The background system generally has a module for users' personal information (see the figure below). In order to enhance users' experience, the system will open the function of custom avatar, so that users can upload custom images to replace the default system avatar. This paper will be implemented through Vue+SpringBoot.

2, Vue image clip upload component

3, Write front-end upload avatar function

  • After understanding the function of Vue image clip upload component, it is quite easy to write the foreground upload function of custom avatar. We only need to embed this component into the personal information page and write the corresponding events.
<template>
  <div class="app-container">
		 ...
          <div slot="header" class="clearfix">
            <span>personal information</span>
          </div>
          <div>
            <div style="text-align: center">
              <div class="el-upload">
                <myUpload

                  v-model="showDialog"
                  :headers="headers"
                  :url="baseApi+'/api/user/updateAvatar'"
                  @crop-upload-success="cropUploadSuccess"
                />
                <img
                  :src="
                    user.avatarUrl
                      ? baseApi + '/file/' + user.avatarUrl
                      : Avatar
                  "
                  title="Click upload Avatar"
                  class="avatar"
                  @click="toggleShow"
                >
			  ...
              </div>
            </div>
          </div>
		..
  </div>
</template>

<script>
// Use avatar upload component
import myUpload from 'vue-image-crop-upload'
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import store from '@/store'
import Avatar from '@/assets/images/avatar.png'
export default {
  name: 'Center',
  components: { myUpload },
  data() {
    return {
      showDialog: false,
      Avatar: Avatar,
      headers: {
        'Authorization': getToken()
      },
      ...
    }
  },
  computed: {
    ...mapGetters([
      'user',
      'baseApi'
    ])
  },

  methods: {
    // Click the avatar to open the upload window
    toggleShow() {
      this.showDialog = !this.showDialog
    },
    // Reload information after successful upload
    cropUploadSuccess(jsonData, field) {
      store.dispatch('getInfo').then(() => { })
    },
   	...
  }
}
</script>
...
  • The page effect is as follows:

4, Write background upload user avatar interface

  • With the front-end page, you need to implement the corresponding interface in the background. Think about what functions the interface needs to have?
  1. The avatar file uploaded from the front-end component needs to be saved to the server;
  2. The user avatar path saved on the server needs to be stored in the user information table.

4.1 save the avatar file uploaded by the front-end component to the server

  • We need to establish an upload file information table and an operation service class for uploading files to save files.
  1. Upload file information table
/**
 * Document information table
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@ApiModel(value = "User information")
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("upload_file")
public class UploadFile implements Serializable {

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * Actual file name
     */
    private String realName;

    /**
     * file name
     */
    private String fileName;

    /**
     * File master name
     */
    private String primaryName;

    /**
     * File extension
     */
    private String extension;

    /**
     * Storage path
     */
    private String path;

    /**
     * file type
     */
    private String type;

    /**
     * file size
     */
    private Long size;

    /**
     * Uploader
     */
    private String uploader;


    private Timestamp createTime;


    @Override
    public String toString() {
        return "UploadFile{" +
                "fileName='" + fileName + '\'' +
                ", uploader='" + uploader + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

  1. Upload file DAO
/**
 * File upload DAO interface
 *
 * @author zhuhuix
 * @date 2021-07-19
 */
@Mapper
public interface UploadFileMapper extends BaseMapper<UploadFile> {

}

  1. Specific implementation class of upload file tool
/**
 * File upload interface definition
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
public interface UploadFileTool {

    /**
     * File upload
     *
     * @param uploader  Uploader
     * @param realName  Actual file name
     * @param multipartFile file
     * @return Upload information
     */
   UploadFile upload(String uploader, String realName, MultipartFile multipartFile);
}

/**
 * File upload implementation class
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UploadFileToolImpl implements UploadFileTool {

    private final UploadFileMapper uploadFileMapper;

    @Value("${uploadFile.path}")
    private String path;

    @Value("${uploadFile.maxSize}")
    private long maxSize;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UploadFile upload(String uploader, String realName, MultipartFile multipartFile) {
        //Check file size
        if (multipartFile.getSize() > maxSize * Constant.MB) {
            throw new RuntimeException("File upload size limit exceeded" + maxSize + "MB");
        }
        //Get the main file name and extension of the uploaded file
        String primaryName = FileUtil.mainName(multipartFile.getOriginalFilename());
        String extension = FileUtil.extName(multipartFile.getOriginalFilename());
        //Get file type based on file extension
        String type = getFileType(extension);
        //Time stamp uploaded files
        LocalDateTime date = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddhhmmssS");
        String nowStr = "-" + date.format(format);
        String fileName = primaryName + nowStr + "." + extension;

        try {
            String filePath = path + type + File.separator + fileName;
            File dest = new File(filePath).getCanonicalFile();
            if (!dest.getParentFile().exists()) {
                if (ObjectUtil.isNull(dest.getParentFile().mkdirs())) {
                    throw new RuntimeException("Failed to upload file: error creating directory");
                }
            }
            multipartFile.transferTo(dest);
            if (ObjectUtil.isNull(dest)) {
                throw new RuntimeException("Failed to upload file");
            }

            UploadFile uploadFile = new UploadFile(null, realName, fileName, primaryName,
                    extension, dest.getPath(), type, multipartFile.getSize(),
                    uploader, Timestamp.valueOf(LocalDateTime.now()));
            if (uploadFileMapper.insert(uploadFile) > 0) {
                return uploadFile;
            }
            throw new RuntimeException("Failed to upload file");

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }

    /**
     * Give the file type according to the file extension
     *
     * @param extension File extension
     * @return file type
     */
    private static String getFileType(String extension) {
        String document = "txt doc pdf ppt pps xlsx xls docx csv";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(extension)) {
            return "image";
        } else if (document.contains(extension)) {
            return "document";
        } else if (music.contains(extension)) {
            return "music";
        } else if (video.contains(extension)) {
            return "video";
        } else {
            return "other";
        }
    }
}

4.2 store the user avatar path saved on the server in the user information table

  1. Add the function of saving avatar information in user information service
/**
 * User information
 *
 * @author zhuhuix
 * @date 2020-04-03
 */
public interface SysUserService {
	....
    /**
     * Modify user Avatar
     * @param file file
     * @return json
     */
    Map<String,String>  updateAvatar(MultipartFile file);

}

/**
 * User information implementation
 *
 * @author zhuhuix
 * @date 2020-04-03
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class SysUserServiceImpl implements SysUserService {

    private final SysUserMapper sysUserMapper;
    private final UploadFileTool uploadFileTool;

	@Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> updateAvatar(MultipartFile file) {
        SysUser sysUser = findByUserName(getCurrentLoginUserName());
		// Call the upload file service to save the avatar
        UploadFile uploadFile = uploadFileTool.upload(sysUser.getUserName(), file.getOriginalFilename(), file);
        // Save avatar path to personal information
        sysUser.setAvatarUrl(uploadFile.getType() + File.separator  + uploadFile.getFileName());
        update(sysUser);
        return new HashMap<String, String>(1) {{
            put("avatar", uploadFile.getFileName());
        }};

    }
	
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysUser update(SysUser user) {
        if (sysUserMapper.updateById(user) > 0) {
            return user;
        }
        throw new RuntimeException("Failed to update user information");
    }

    @Override
    public SysUser findByUserName(String userName) {
        return sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserName, userName));
    }

  

    private String getCurrentLoginUserName() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            throw new RuntimeException("The login status has expired");
        }
        if (authentication.getPrincipal() instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            return (userDetails.getUsername());
        }
        throw new RuntimeException("The information for the current login cannot be found");
    }

}

4.3 compile API for user update avatar information

  • Finally, you only need to add the user update avatar information API interface in the Controller layer for the front-end call
@ApiOperation("Modify user Avatar")
    @PostMapping(value = "/updateAvatar")
    public ResponseEntity<Object> updateAvatar(@RequestParam MultipartFile avatar) {
        return  ResponseEntity.ok(sysUserService.updateAvatar(avatar));
    }

5, Front and rear end joint commissioning

6, Source code

https://gitee.com/zhuhuix/startup-backend
https://github.com/zhuhuix/startup-backend

Topics: Java Spring Boot Vue