Java十天上手做一个自己的web商城笔记-上传头像(7)

本文详细介绍了使用SpringBoot、MyBatis和MySQL实现用户头像上传的过程,包括持久层、业务层和控制层的代码实现,异常处理,以及前端页面的交互。同时,文章涵盖了文件上传的限制、单元测试和异常类的设计,以及登录后头像显示的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 该系列博客主要记录笔者的开发过程,参考B站系列视频:【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战_哔哩哔哩_bilibili

所用的一些版本信息:

IDEA开发、JDK1.8版本以上、maven3.61版本以上,springboot,DataGrip管理数据库

上传头像的页面如下:

1.上传头像-持久层

1.1规划SQL语句

将对应文件保存在操作系统,文件路径记录在t_user表的avatar字段下。需要依据更新用户avatar字段的SQL语句。

1.2 设计接口和抽象方法

store\src\main\java\com\cy\store\mapper\UserMapper.java

    /**
     * @Param("uid1") uid2 主要是做名称装换, 后面那个uid2的值注入到sql语句中的uid1中
     * 根据用户id修改头像
     * @param uid
     * @param avatar
     * @param modifiedUser
     * @param modifiedTime
     * @return
     */
    Integer updateAvatarByUid(@Param("uid") Integer uid, 
                              @Param("avatar") String avatar, 
                              @Param("modifiedUser") String modifiedUser, 
                              @Param("modifiedTime") Date modifiedTime);

1.3 接口的映射

store\src\main\resources\mapper\UserMapper.xml

    <update id="updateAvatarByUid">
        UPDATE t_user SET
            avatar = #{avator},
            modified_user = #{modifiedUser},
            modified_time = #{modifiedTime}
        where uid=${uid}
    </update>

1.4 单元测试

store\src\test\java\com\cy\store\mapper\UserMapperTests.java

    @Test
    public void updateAvtarByUid(){
        Integer rows = userMapper.updateAvatarByUid(29, "/upload/avatar.png", "管理员", new Date());
    }

2.上传头像-业务层

2.1 规划异常

1.各种情况导致用户数据不存在。(异常已有)

2.未知异常产生。(异常已有)

2.2 设计接口和抽象方法

store\src\main\java\com\cy\store\service\IUserService.java

    /**
     * 修改用户的头像
     * @param uid 用户id
     * @param avatar 头像
     * @param username 用户姓名
     */
    void changeAvatar(Integer uid, String avatar, String username);

store\src\main\java\com\cy\store\service\impl\UserServiceImpl.java

    @Override
    public void changeAvatar(Integer uid, String avatar, String username) {
        User result = userMapper.findByUid(uid);
        if(result == null || result.getIsDelete()==1){
            throw new UserNotFoundException("用户数据不存在");
        }
        Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, new Date());
        if(rows!=1){
            throw new UpdateException("更新数据时产生未知异常");
        }
    }

2.3 单元测试

store\src\test\java\com\cy\store\service\UserServiceTests.java

    @Test
    public void changeAvatar() {
        userService.changeAvatar(29, "/123/123.png", "guanli");
    }

3.上传头像-控制层

3.0 规划异常

由于上传头像是传文件,需要规划产生的异常。

首先创建文件基类异常:

FileUploadException 父类

子类:
FileEmptyException 空文件异常
FileSizeException  文件大小超出限制异常
FileTypeException  文件类型异常
FileUploadIOException  文件读写异常
FileStateException 文件状态异常

代码略 

3.1 处理异常

在基类BaseController中进行统一处理:

store\src\main\java\com\cy\store\controller\BaseController.java

        else if (e instanceof FileEmptyException) {
            result.setState(6000);
        } else if (e instanceof FileSizeException) {
            result.setState(6001);
        } else if (e instanceof FileTypeException) {
            result.setState(6002);
        } else if (e instanceof FileStateException) {
            result.setState(6003);
        } else if (e instanceof FileUploadIOException) {
            result.setState(6004);
        }

并在handleException这个方法上添加新的异常的参数

3.2 设计请求

url:/users/change_avator
请求类型:POST
参数:HTTPSession, MultipartFile file
响应:JsonResult<String>

3.3 处理请求

该部分需要处理文件,所以代码较长

store\src\main\java\com\cy\store\controller\UserController.java下编写如下代码:

    /** 上传头像最大值 */
    public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
    /** 上传限制文件类型 */
    public static final List<String> AVATAR_TYPE = new ArrayList<>();
    static {
        AVATAR_TYPE.add("image/jpeg");
        AVATAR_TYPE.add("image/png");
        AVATAR_TYPE.add("image/bmp");
        AVATAR_TYPE.add("image/gif");
    }

    /**
     * MultipartFile SpringMVC提供的接口,包装了获取文件类型的数据(任何类型的file),使用时申明参数,Springboot自动将数据赋值给参数
     * @RequestParam("file1") file2 将前端表单(请求参数)file1,注入到请求方法参数上file2
     */
    @RequestMapping("change_avatar")
    public JsonResult<String> changeAvatar(HttpSession session,
                                           @RequestParam("file") MultipartFile file){
        System.out.println("进入修改接口");
        //判断文件是否合规
        if(file.isEmpty()){
            throw new FileEmptyException("文件为空");
        }
        if(file.getSize()>AVATAR_MAX_SIZE){
            throw new FileSizeException("文件超出大小限制");
        }
        String contentType = file.getContentType();
        if(!AVATAR_TYPE.contains(contentType)){
            throw new FileTypeException("文件类型不支持");
        }
        //上传的文件目录结构.../upload/file.png
        String parent = session.getServletContext().getRealPath("upload");
        //upload 可能找不到
        //File指向路径 File不存在则创建目录
        File dir = new File(parent);
        if(!dir.exists()){
            dir.mkdirs();
        }
        //获取文件名称,用UUID用具类生成新的字符串作为文件名
        String originalFilename = file.getOriginalFilename();
        System.out.println("originalFilename ="+originalFilename);
        int index = originalFilename.lastIndexOf(".");
        String suffix = originalFilename.substring(index);
        String filename = UUID.randomUUID().toString().toUpperCase() + suffix;
        //先在目录下创建一个空文件,再拷贝写入空文件
        File dest = new File(dir, filename);
        try {
            file.transferTo(dest); //将file文件数据写入dest文件中,两个文件后缀一致
        } catch (FileStateException e){
            throw new FileStateException("文件状态异常");
        } catch (IOException e) {
            throw new FileUploadIOException("文件读写异常");
        }
        //修改数据库
        String avatar = "/upload/" + filename;
        userService.changeAvatar(getuidFromSession(session), avatar, getusernameFromSession(session));
        //返回头像路径给前端,后面用作展示
        return new JsonResult<String>(OK, avatar);
    }

4.上传头像-前端页面

这里直接使用表单进行文件类型上传(方便测试,后面需要用ajax进行上传),需要给表单添加属性 enctype="multipart/form-data",不会将目标文件的数据结构做修改上传。

这里添加标签如下:

action = "/user/change_avatar"
method="post"
enctype="multipart/form-data"

5.解决Bug

5.1 手动修改上传头像的默认大小

SpringMVC默认1MB的文件可以上传,需要手动修改。

1)在配置文件中进行配置

 2通过Java代码来设置文件的上传限制。

在主类(store\src\main\java\com\cy\store\StoreApplication.java)中进行配置,可以定义一个方法,使用@Bean,@configuration修饰。

package com.cy.store;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

import javax.servlet.MultipartConfigElement;

@SpringBootApplication
//mapperScan注解指定当前项目的mapper接口路径的位置,在项目启动时会自动加载所有的接口文件
@MapperScan("com.cy.store.mapper")
public class StoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(StoreApplication.class, args);
    }

    @Bean
    public MultipartConfigElement getMultipartConfigElement(){
        //创建一个配置的工厂类对象
        MultipartConfigFactory factory = new MultipartConfigFactory();

        //设置需要创建的对象的相关信息
        factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
        factory.setMaxRequestSize(DataSize.of(15, DataUnit.MEGABYTES));

        //工厂类创建MultipartConfigElement对象
        return factory.createMultipartConfig();
    }
}

5.2 前端页面显示头像

在页面中通过ajax请求提交文件,后端返回json串后,解析出data数据设置到img头像标签的src属性上:

在store\src\main\resources\static\web\upload.html 中添加如下代码(在此之前要将前面的表单提交代码删除掉)

		<script type="text/javascript">
			$("#btn-change-avatar").click(function(){
				$.ajax({
					url:"/users/change_avatar",
					type: "POST",
					data: new FormData($('#form-change_avatar')[0]),
					processData: false,//关闭处理数据(否则会按照串的形式处理数据)
					contentType: false,// 关闭提交数据的形式(否则会按照串的形式提交数据)
					dataType:"JSON",
					success:function (json){
						console.log(json)
						if(json.state == 200){
							alert("头像上传成功");
							// 将服务器端返回头像设置到img标签的src属性上
							$("#img-avatar").attr("src", json.data);
						}else{
							alert("头像上传失败" + json.message);
						}
					},
					error: function(xhr){
						alert("头像上传时产生未知异常" + xhr.message)
					}
				});
			});
		</script>

5.3 登录后直接显示头像

更新头像成功后,将头像路径保存在cookie中,每次检测到用户打开上传头像页面,在这个页面中通过ready()方法自动检测读取头像并设置到src属性上。

1.设置cookie的值

在login.html中设置cookie

2.在upload.html中引入cookie

<script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>

3.使用ready()读头像

upload.html中添加代码如下:

		<script type="text/javascript">
			$(document).ready(function(){
				let avatar = $.cookie("avatar");
				$("#img-avatar").attr("src", avatat);
			})
			$("#btn-change-avatar").click(function(){
				$.ajax({
					url:"/users/change_avatar",
					type: "POST",
					data: new FormData($('#form-change_avatar')[0]),
					processData: false,//关闭处理数据(否则会按照串的形式处理数据)
					contentType: false,// 关闭提交数据的形式(否则会按照串的形式提交数据)
					dataType:"JSON",
					success:function (json){
						console.log(json)
						if(json.state == 200){
							alert("头像上传成功");
							// 将服务器端返回头像设置到img标签的src属性上
							$("#img-avatar").attr("src", json.data);
							$.cookie("avatar", json.data.avatar, {expires:7}) //存活时间的单位为天
						}else{
							alert("头像上传失败" + json.message);
						}
					},
					error: function(xhr){
						alert("头像上传时产生未知异常" + xhr.message)
					}
				});
			});
		</script>

这样就成功实现了,但由于浏览器存在缓存,所以代码正确也可能导致功能不正确,需要清浏览器缓存重试。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值