当前位置:网站首页>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/upload
5. 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
边栏推荐
- 5. Use RecyclerView to elegantly achieve waterfall effect
- Detailed explanation of Golang garbage collection mechanism
- Impressions of Embrace Jetpack
- Win11怎么在右键菜单添加一键关机选项
- PHY6222蓝牙5.2支持MESH组网M0内核超低功耗
- win10系统更新错误代码0x80244022怎么办
- KiCad Common Shortcuts
- Yolov5 official code reading - prior to transmission
- Network Security Packet Capture
- yolov5官方代码解读——前向传播
猜你喜欢
How to reinstall Win7 system with U disk?How to reinstall win7 using u disk?
Redis的线程模型
Win11系统找不到dll文件怎么修复
Win11声卡驱动如何更新?Win11声卡驱动更新方法
What should I do if the Win10 system sets the application identity to automatically prompt for access denied?
为vscode配置clangd
STM32LL库使用——SPI通信
How to add a one-key shutdown option to the right-click menu in Windows 11
Mapreduce环境详细搭建和案例实现
MATLAB图形加标注的基本方法入门简介
随机推荐
Win11 computer off for a period of time without operating network how to solve
Win10电脑不能读取U盘怎么办?不识别U盘怎么解决?
开心一下,9/28名场面合集
Installation and configuration of Spark and related ecological components - quick recall
Compilation error D8021: Invalid numeric argument '/Wextra' cl command line error d8021 invalid numeric argument '/Wextra'
KiCad Common Shortcuts
Win11 system cannot find dll file how to fix
二叉树创建之层次法入门详解
pygame拖动条的实现方法
使用libcurl将Opencv Mat的图像上传到文件服务器,基于post请求和ftp协议两种方法
MATLAB绘制平面填充图入门详解
A clean start Windows 7?How to load only the basic service start Windows 7 system
How to reinstall Win7 system with U disk?How to reinstall win7 using u disk?
推开机电的大门《电路》(一):电压,电流,参考方向
MATLAB绘图函数ezplot入门详解
FP6195耐压60V电流降压3.3V5V模块供电方案
pytorch模型转libtorch和onnx格式的通用代码
FP7195转模拟恒流调光芯片在机器视觉光源的应用优势
Failed to install using npx -p @storybook/cli sb init, build a dedicated storybook by hand
How to simulate 1/3 probability with coins, and arbitrary probability?