记录第一次做图片服务后端
后端架构为:SpringBoot + Jpa + MySQL + JWT
本文同步在我的博客SPIN 自旋
需求
山大迷踪中关于图片的需求有:用户头像、发布迷踪帖(含照片)、发布匹配帖(含照片)、积分商城初始化(商品图片)。
分析
分析之后得出,后端应实现如下功能:
上传图片
保存图片
图片回传
删除废弃的头像、未过审帖子的照片、匹配成功后两帖子的照片
代码实现(以用户头像为例)
上传图片
采用formdata格式,直接上传图片文件,在后端使用MultipartFile类来接收。
Controller代码如下:
@PutMapping("/changeavatar")
public Result changeAvatar(MultipartFile avatar, HttpServletRequest request) {
String token = request.getHeader("token");//从请求头中拿到token
User user = userService.getUserByToken(token);//通过token来拿到用户实体
userService.changeAvatar(user,avatar);// 修改该用户的头像
return Result.success(JwtUtil.refreshToken(token));//返回成功码和新的token
}
其中,UserService.changeAvatar方法的实现如下:
@Override
public void changeAvatar(User user, MultipartFile avatar) {
String avatarPath = ImgUtil.uploadAvatar(avatar);//保存图片到服务器,后面会贴出这个方法的代码
if(avatarPath!=null&&user.getAvatar()!=null)ImgUtil.deleteImg(user.getAvatar());//存在旧头像则删除
user.setAvatar(avatarPath);//保存用户头像url
modifyUser(user);//更新用户
}
保存图片到服务器
上面我们已经拿到了图片的MutipartFile对象,现在我们把这个对象写成文件,保存在服务器的本地目录下。
这个过程,就是上文中说到的ImgUtil.uploadAvatar方法,代码如下:
package misstrace.Util;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class ImgUtil {
// 定义头像存储地址
private static final String AVATAR_PATH = "/project/misstrace/tomcat8port8080/webapps/avatar/";
// 定义访问头像的路径根部 http
private static final String AVATAR_LOAD_PATH = "http://xxx.xxx.xxx/misstrace/avatar/";
//将MultipartFile压缩保存
public static String uploadAvatar(MultipartFile avatar) {
//获得上传文件的名称
String rawFileName = avatar.getOriginalFilename();
//生成随机uuid,连接到原文件名前面,防止重名
String uuid = UUID.randomUUID().toString().replace("-","");
String newFileName = uuid+"-"+rawFileName;
//压缩图片,并保存在上述路径
Boolean flag = zipAvatar(avatar,AVATAR_PATH+newFileName);
if(!flag)return null;
return AVATAR_LOAD_PATH+newFileName;
}
// 压缩图片并保存在该目录下
public static Boolean zipAvatar(MultipartFile img,String path) {
try {
//先压缩并保存图片
Thumbnails.of(img.getInputStream()).size(128,128) //压缩尺寸 范围(0.00--1.00)
.outputQuality(0.4f) //压缩质量 范围(0.00--1.00)
.toFile(path); //输出路径
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}
上面的注释也说的很清楚了,我使用Thumbnails压缩了图片(这样能加速后续的“图片回传”功能,减轻服务器压力)
Thumbnails的依赖如下(放入pom.xml的dependencies标签中):
<!--图片处理thumbnailator-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.17</version>
</dependency>
图片回传
在保存图片的时候,我传回的是带有图片名的url,这个url将一路传到前端手里,然后由前端来请求加载这个图片。
那么如何让前端通过url就能访问头像文件呢?
我这里采用的是tomcat,广播出去静态资源(可恶的华为云,安全组默认关掉了所有端口。。)。
后面其实还是使用nginx做了转发,这样能不暴露进程的端口。
再后来,就是研究了半天域名和https(ssl证书)的问题,虽然域名解析和https都能用,但考虑到我的域名只有半年期限了,还是继续使用原始的服务器ip了。
删除废弃的图片
直接上代码(在ImgUtil类中):
//通过url路径删除图片
public static Boolean deleteImg(String imgLoadPath) {
boolean flag = false;
String filePath = "/project/misstrace/tomcat8port8080/webapps/"+imgLoadPath.substring(33);
//根据路径创建文件对象
File file = new File(filePath);
//路径是个文件且不为空时删除文件
if(file.isFile()&&file.exists()){
flag = file.delete();
}
//删除失败时,返回false
return flag;
}
总结
总体来说,这部分服务的实现过程还是很愉快的,一个从0到1的过程,”接口生效“的正向反馈让我有些上头。
然而在上手的时候,我还是意识到对异常处理的陌生。