当前位置:网站首页>3.用户上传头像
3.用户上传头像
2022-08-02 14:10:00 【鱼子酱:P】
还是三层架构,首先考虑数据访问层,这一层没有什么处理,因为是把头像存到硬盘里没有存到数据库里;业务层需要就是上传完头像后更新headurl,服务端就需要提供一个改变头像路径的功能;上传文件这个事就在controller表现层里实现就好了。因为啊MultipartFile是属于表现层的一个对象,要是传给了service就产生了耦合了,不太合适。


首先上传头像得有一个存储头像的路径,这个路径不能是固定的,因为在本地开发和部署到服务器肯定不一样,目前存到本地,后期也会存到云服务器上。在application.properties里配上头像上传路径。
1. 大体思路
①用户点击首页面【账号设置】按钮,getSettingPage()会返回静态资源【/site/setting】,进入到设置页面,执行UserController的控制器方法;
②我们点击【上传头像】按钮后,发送【/user/upload】,执行UserController的控制器方法uploadHeader():首先对空值进行处理,然后用substring分割出文件后缀,png或者jpg等等。如果没有后缀就提示文件格式不正确。对用户上传的图片重命名,用之前写的生成uuid的方法加上分割出来的文件后缀。将文件存储到我们在配置文件中设置的路径下,并更新当前user的headerUrl属性为指定格式的路径;
③当我们需要访问头像(即user的headerUrl属性)时,控制器方法getHeader()会根据headerUrl,将对应目录下的头像复制出来。
2. 用户控制器-上传头像
这里用到的是Spring MVC的multipartFile,头像的存储和获取直接在controller层操作。新建一个UserController。将类的访问路径设为/user。
转载:初步理解MultipartFile - 简书 (jianshu.com)
MultipartFile是SpringMVC提供简化上传操作的工具类。
在不使用框架之前,都是使用原生的HttpServletRequest来接收上传的数据,文件是以二进制流传递到后端的,然后需要我们自己转换为File类。使用了MultipartFile工具类之后,我们对文件上传的操作就简便许多了。
MultipartFile主要是用表单的形式进行文件上传,在接收到文件时,可以获取文件的相关属性,比如文件名、文件大小、文件类型等等。
- 第一个方法,用于返回个人设置页面,直接返回模板路径。
- 然后上传头像的方法,这里从容器获取两个对象,一个是MultiparFile,也就是从浏览器传过来的头像文件,一个是model,用于模型返回信息。
- 首先对空值进行处理,然后用substring分割出文件后缀,png或者jpg等等。如果没有后缀就提示文件格式不正确。对用户上传的图片重命名,用之前写的生成uuid的方法加上分割出来的文件后缀。
- 再在我们指定的文件存放位置新建一个文件,文件名使用生成的名字,并记录异常,将异常向上抛出,用于之后的处理。然后从hostHolder里获取当前用户,更新头像路径。
package com.nowcoder.mycommunity.controller;
@Controller
@RequestMapping("/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
//注入文件的上传路径
@Value("${community.path.upload}")
private String uploadPath;
//注入域名
@Value("${mycommunity.path.domin}")
private String domain;
//访问路径
@Value("${server.servlet.context-path}")
private String contextPath;
@Autowired
private UserService userService;
@Autowired
private HostHolder hostHolder;
//进入账号设置
@RequestMapping(path="/setting",method = RequestMethod.GET)
public String getSettingPage(){
return "/site/setting";
}
//上传头像
@RequestMapping(path = "/upload", method = RequestMethod.POST)
public String uploadHeader(MultipartFile headerImage, Model model){
//如果没上传头像,就点击上传头像按钮
if(headerImage == null){
model.addAttribute("error","您还没有选择图片!");
return "/site/setting";
}
//获取图片后缀名
String fileName = headerImage.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf("."));
if(StringUtils.isBlank(suffix)){ //如果后缀名为空
model.addAttribute("error","文件格式不正确!");
return "/site/setting";
}
//生成随机的文件名
fileName = CommunityUtil.generateUUID() + suffix;
File dest = new File(uploadPath + "/" + fileName);
try {
headerImage.transferTo(dest);
} catch (IOException e) {
logger.error("上传文件失败:" + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
//到此就可以正常进行了
//更新当前用户头像的路径(Web访问路径)
//格式:http://localhost:8080/community/user/header/xxx.png
User user = hostHolder.getUser();
String headerUrl = domain + contextPath + "/user/header/" + fileName;
userService.updateHeader(user.getId(), headerUrl);
return "redirect:/index";
}
//获取头像(和上面头像设置时的路径格式保持一致)
@RequestMapping(path = "/header/{fileName}", method = RequestMethod.GET)
public void getHeader(@PathVariable("fileName") String fileName, HttpServletResponse response){
//服务器存放路径
fileName = uploadPath + "/" + fileName;
//文件后缀
String suffix = fileName.substring(fileName.lastIndexOf("."));
//响应图片(浏览器响应图片时,为此写法)
response.setContentType("image/" + suffix);
//获取字节流
try (
//此为java7写法,这里面声明的变量会自动加finally,在里面自动关闭
//而输出流会被SpringMVC自动关闭
FileInputStream fis = new FileInputStream(fileName);
OutputStream os = response.getOutputStream();
){
byte[] buffer = new byte[1024];
int b = 0;
while((b = fis.read(buffer)) != -1){
os.write(buffer, 0, b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}3. 更新用户头像方法
在UserService类中添加方法
还是从dao层向controller开发,由于头像直接存在本地,没有存到数据库,这里不涉及dao层。
service层主要处理user表里的headUrl,这个方法在userMapper里写过,直接调用就可以。
//更新用户头像
public int updateHeader(int userId, String headurl){
return userMapper.updateHeader(userId, headurl);
}4. 配置文件
添加文件的上传存储路径。
# 上传资源存放的位置
community.path.upload=e:/nowcoder/data/upload5. html
①首页index.html:进入【账号设置】。
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item text-center" href="site/profile.html">个人主页</a>
<a class="dropdown-item text-center" th:href="@{/user/setting}">账号设置</a>
<a class="dropdown-item text-center" th:href="@{/logout}">退出登录</a>
<div class="dropdown-divider"></div>
<span class="dropdown-item text-center text-secondary" th:utext="${loginUser.username}">nowcoder</span>
</div>
②账号设置页面setting.html:上传头像
<!-- 上传头像 -->
<h6 class="text-left text-info border-bottom pb-2">上传头像</h6>
<form class="mt-5" method="post" enctype="multipart/form-data" th:action="@{/user/upload}">
<div class="form-group row mt-4">
<label for="head-image" class="col-sm-2 col-form-label text-right">选择头像:</label>
<div class="col-sm-10">
<div class="custom-file">
<!-- name需要与控制器方法中形参名相同 -->
<input type="file" th:class="|custom-file-input ${error!=null?'is-invalid':''}|"
id="head-image" name="headerImage" lang="es" required="">
<label class="custom-file-label" for="head-image" data-browse="文件">选择一张图片</label>
<div class="invalid-feedback" th:text="${error}">
该账号不存在!
</div>
</div>
</div>
</div>
<div class="form-group row mt-4">
<div class="col-sm-2"></div>
<div class="col-sm-10 text-center">
<button type="submit" class="btn btn-info text-white form-control">立即上传</button>
</div>
</div>
</form边栏推荐
- Mysql connection error solution
- Please make sure you have the correct access rights and the repository exists.问题解决
- DP1332E刷卡芯片支持NFC内置mcu智能楼宇/终端poss机/智能门锁
- FP7128内置MOS降压恒流调光深度0.01%高辉共阳调光方案
- 日常-笔记
- MATLAB绘图函数fplot详解
- Win11怎么在右键菜单添加一键关机选项
- LeetCode2 电话号码的字母组合
- What should I do if I install a solid-state drive in Win10 and still have obvious lags?
- FP7195转模拟恒流调光芯片在机器视觉光源的应用优势
猜你喜欢
随机推荐
Daily - Notes
Win11电脑一段时间不操作就断网怎么解决
【系统设计与实现】基于flink的分心驾驶预测与数据分析系统
Win10 cannot directly use photo viewer to open the picture
FP7195降压恒流PWM转模拟调光零压差大功率驱动方案原理图
Use libcurl to upload the image of Opencv Mat to the file server, based on two methods of post request and ftp protocol
二叉树遍历之后序遍历(非递归、递归)入门详解
Actual combat Meituan Nuxt +Vue family bucket, server-side rendering, mailbox verification, passport authentication service, map API reference, mongodb, redis and other technical points
利用plot_surface命令绘制复杂曲面入门详解
Binder机制(下篇)
STM32LL库——USART中断接收不定长信息
win10无法直接用照片查看器打开图片怎么办
Binder机制(中篇)
Configure clangd for vscode
ASR6601牛羊定位器芯片GPS国内首颗支持LoRa的LPWAN SoC
Use tencent cloud builds a personal blog
STM32LL库使用——SPI通信
win10怎么设置不睡眠熄屏?win10设置永不睡眠的方法
mysql的索引结构为什么选用B+树?
Win11 keeps popping up User Account Control how to fix it









