目录
设计思路
效果展示
编辑
分析
前后端交互接口
请求
响应
代码实现和详细注释
数据库设计
自定义资源映射
前后端交互
客户端开发
服务器开发
实现这个功能只要弄清楚以下几点即可:
POST /user/subphoto
Content-Type: multipart/form-data
processData: false
data: new FormData(document.querySelector("#forminfo")) //form 表单对象
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 200,
"msg": "",
"data": photoPathRelative //图片相对路径
}
用户表设计如下:
create table userinfo(
id int primary key auto_increment,
username varchar(100) unique,
password varchar(65) not null,
photo varchar(500) default "img/default.jpg",
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
`state` int default 0,
nickname varchar(50) not null,
realname varchar(50) default "",
idcard varchar(50) default "",
gitee varchar(200) default ""
) default charset 'utf8mb4';
创建一个类,名为 StaticResourcesConfig,实现 WebMvcConfigurer 接口下的 addResourceHandlers 方法,此方法就是用来注册路由的。
代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration //一定不要忘了这个注解
public class StaticResourcesConfig implements WebMvcConfigurer {
/**
* 自定义资源映射
* 由于在浏览器界面上传图片,而 Spring boot 程序是感知不到的,因此需要自定义资源映射
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:upload/");
}
}
addResourceHandler("/upload/**"):表示访问的时候路径上要加上upload,不然访问不到。
addResourceLocations("file:upload/"):你图片上传的路径,我的图片上传就在upload文件中。
//隐藏修改头像和提交控件
jQuery("#choose-photo").hide();
jQuery("#sub-photo").hide();
//修改头像
function updatePhoto() {
//点击头像,就会弹出文件选择框
jQuery("#choose-photo").click();
//当 #choose-photo 内容改变时触发
jQuery("#choose-photo").change(function () {
// //点击 submit 提交表单
var fd = new FormData(document.querySelector("#forminfo"));
fd.append("myphoto", jQuery("#choose-photo").val());
jQuery.ajax({
type: "POST",
url: "/user/subphoto",
data: fd,
// 想让文件传输格式为 form 表单设置的格式,那么就必须设置以下两个属性
contentType: false,
processData: false,
success: function (result) {
if (result != null && result.code == 200) {
//刷新网页
alert("头像修改成功!");
location.href = location.href;
} else {
alert("头像上传失败,请稍后重试!");
}
}
});
});
}
/**
* 修改用户头像
* @param request
* @param photo
* @return
*/
@RequestMapping("/subphoto")
public AjaxResult updatePhoto(HttpServletRequest request,
@RequestPart("myphoto") MultipartFile photo) {
//非空校验
if(photo == null) {
return AjaxResult.fail(403, "图片错误!");
}
//要上传的文件名
String originalFileName = photo.getOriginalFilename();
//获取用户信息(1.删除旧头像需要原来的旧头像的路径 2.修改图片需要用户 id)
UserInfo userInfo = UserSessionUtils.getUser(request);
if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername()) ||
!StringUtils.hasLength(userInfo.getPassword())) {
return AjaxResult.fail(403, "参数错误!");
}
if(!userInfo.getPhoto().equals("img/default.jpg")) {
//不是修改默认头像的话就将旧头像删除即可
File file = new File(AppVariable.IMG_PATH_ABSOLUTE
+ userInfo.getPhoto().split("/")[2]);
file.delete();
}
//获取文件后缀
String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
//生成图片名称,使用 UUID 避免相同图片名冲突,加上图片后缀
String photoName = UUID.randomUUID().toString() + suffix;
//图片保存路径(绝对路径/相对路径)
//这里为什么还要用相对路径,只用绝对路径不行么?
//因为禁止浏览器访问本地磁盘绝对路径路径,因此最简单的办法就是配置一个绝对路径用来保存文件,一个相对路径提供给浏览器访问
String photoPathAbsolute = AppVariable.IMG_PATH_ABSOLUTE + photoName; //绝对路径
String photoPathRelative = AppVariable.IMG_PATH_RELATIVE + photoName; //相对路径
//生成文件(绝对路径)
File saveFile = new File(photoPathAbsolute);
try {
//将上传文件绝对路径保存到服务器文件系统
photo.transferTo(saveFile);
//保存图片相对路径到数据库中
userService.updatePhotoById(userInfo.getId(), photoPathRelative);
//修改评论
userInfo.setPhoto(photoPathRelative);
updateInfoUtils.updateSessionAndComment(request, userInfo);
} catch (IOException e) {
e.printStackTrace();
}
//将图片相对路径返回给前端
return AjaxResult.success(photoPathRelative);
}