当前位置:网站首页>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边栏推荐
- FP6296锂电池升压 5V9V12V内置 MOS 大功率方案原理图
- Win10系统设置application identity自动提示拒绝访问怎么办
- The SSE instructions into ARM NEON
- Please make sure you have the correct access rights and the repository exists.问题解决
- IPV4和IPV6是什么?
- 基于最小二乘法的线性回归分析方程中系数的估计
- win11一直弹出用户账户控制怎么解决
- pygame绘制弧线
- 关于c语言的调试技巧
- Win10 computer can't read U disk?Don't recognize U disk how to solve?
猜你喜欢

将SSE指令转换为ARM NEON指令

二叉树创建之层次法入门详解

In-depth understanding of Golang's Map

pygame绘制弧线

Open the door to electricity "Circuit" (3): Talk about different resistance and conductance

使用 腾讯云搭建一个个人博客

13.56MHZ刷卡芯片CI521兼容cv520/ci520支持A卡B卡MIFARE协议

Use tencent cloud builds a personal blog

FP7195降压恒流PWM转模拟调光零压差大功率驱动方案原理图

win10怎么设置不睡眠熄屏?win10设置永不睡眠的方法
随机推荐
What is Win10 God Mode for?How to enable God Mode in Windows 10?
How to update Win11 sound card driver?Win11 sound card driver update method
pygame拖动条的实现方法
一篇文章彻底理解Redis的持久化:RDB、AOF
Win11 computer off for a period of time without operating network how to solve
Please make sure you have the correct access rights and the repository exists.问题解决
Letter combination of LeetCode2 phone number
Win10上帝模式干嘛的?Win10怎么开启上帝模式?
Impressions of Embrace Jetpack
What should I do if Windows 10 cannot connect to the printer?Solutions for not using the printer
Win11 system cannot find dll file how to fix
Win11 keeps popping up User Account Control how to fix it
刷卡芯片CI520可直接PIN对PIN替换CV520支持SPI通讯接口
网络安全抓包
vscode镜像
cmake配置libtorch报错Failed to compute shorthash for libnvrtc.so
win10无法直接用照片查看器打开图片怎么办
FP7126降压恒流65536级高辉无频闪调光共阳极舞台灯RGB驱动方案
General syntax and usage instructions of SQL (picture and text)
Win10无法连接打印机怎么办?不能使用打印机的解决方法