上传头像【项目 商城】

简介: 上传头像【项目 商城】

上传头像



1. 上传头像-持久层

1.1 SQL语句的规划


将对应的文件保存在操作系统上,然后再把这个文件的路径记录下来,因为在记录路径的时候是非常方便的,将来如果要打开这个文件可以依据这个路径去找到这个文件。在数据库中需要保存这个文件路径即可。将所有的静态资源(图片、文件、其他资源文件)放到某台电脑上,在把这台电脑作为一台单独的服务器使用。


对应是一个更新用户avatar字段的SQL语句。

update t_user set avatar=?,modified_user=?,modified_time=? where uid=?

1.2 设计接口和抽象方法

UserMapper接口中来定义一个抽象方法用于修改用户的头像。

  /**
     *  @Param("SQL映射文件#{}占位符的变量名"):
     * 解决的问题:当SQL语句的占位符和映射接口方法参数名不一致时,需要将某个参数强行注入到某个占位符变量上时,
     * 可以使用@Param这个注解映射的关系
     * 
     * 根据用户的uid表示修改用户的头像
     * @param uid 用户的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 接口的映射

UserMapper.xml中编写映射的SQL语句

   <!-- pathVariable("user") String username   -->
    <!-- param("user") String username   -->
    <update id="updateAvatarByUid">
        UPDATE t_user
        SET 
            avatar=#{avatar},
            modified_user=#{modifiedUser},
            modified_time=#{modifiedTime}
        WHERE
            uid=#{uid}
    </update>

UserMapper–updateAvatarByUid


测试

在测试类中编写测试的方法

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

2. 上传头像-业务层

2.1 规划异常

1.用户数据不存在,找不到对应的用户的数据

2.更新的时候,各种未知的异常产生

无需重复开发

2.2 设计接口和抽象方法

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

2.3 实现抽象方法

编写业务层的更新用户头像的方法

  @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("更新数据时产生未知的异常");
        }
    }

IUserService–changeAvatar


测试

测试业务层方法执行

   @Test
    public void changeAvatar(){
        userService.changeAvatar(8,"/upload/test.png","test02");
    }

UserServiceTests–changeAvatar


3. 上传头像-控制层

3.1 规划异常

文件异常的父类
  FileUploadException 泛指文件上传的异常(父类)继承RuntimeException
父类是:FileUploadException 
  FileEmptyException 文件为空的异常
  FileSizeException 文件大小超出异常
  FileStateException 上传文件状态异常
  FileTypeException 文件类型异常
  FileUploadIOException 文件读写的异常
五个构造方法显示的声明出来,再去继承相关的父类。

controller | ex


controller–ex–文件上传


3.2 处理异常

在基类BaseController类中进行编写和统一处理。

    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);
        }

在异常统一处理方法的参数列表增加新的异常作为它的参数。

@ExceptionHandler({ServiceException.class,FileUploadException.class})

3.3 设计请求

/users/change_avatar
POST (get请求提交数据2KB)
HttpSession session,MutipartFile file
JsonResult<String>

3.4 实现请求

   /** 设置上传文件的最大值  byte */
    public static final int AVATAR_MAX_SIZE  = 10 * 1024 * 1024;
    /** 限制上传文件的类型*/
    public static final List<String> AVATAR_TYPES  =new ArrayList<>();
    static {
        AVATAR_TYPES.add("images/jpeg");
        AVATAR_TYPES.add("images/png");
        AVATAR_TYPES.add("images/bmp");
        AVATAR_TYPES.add("images/gif");
    }
    /**
     * MultipartFile 接口是由springMVC提供的接口,
     * 这个接口为我们包装了获取文件类型的数据(任何类型的file都可以接受),
     * SpringBoot它整合了SpringMVC,只需要在处理请求的方法参数列表上
     * 声明一个参数类型为MultipartFile的参数,
     * 然后SpringBoot自动将传递给服务的文件的数据
     * 赋值给这个参数
     *
     * @RequestParam() 表示请求中的参数,
     * 将请求中的参数注入到请求处理方法的某个参数上,
     * 如果名称不一致则可以使用@RequestParam() 进行映射
     *
     * @param session
     * @param file
     * @return
     */
    @RequestMapping("change_avatar")
    public JsonResult<String> changeAvatar(HttpSession session,
                                           @RequestParam("file") MultipartFile file){
        // 判断上传的文件是否为空
        if (file.isEmpty()) {
            // 是:抛出异常
            throw new FileEmptyException("上传的头像文件不允许为空");
        }
        // 判断上传的文件大小是否超出限制值
        if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位
            // 是:抛出异常
            throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
        }
        // 判断上传的文件类型是否超出限制
        String contentType = file.getContentType();
        // public boolean list.contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false。
        if (!AVATAR_TYPES.contains(contentType)) {
            // 是:抛出异常
            throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:\n" + AVATAR_TYPES);
        }
        //上传文件.../upload/文件.png
        // 获取当前项目的绝对磁盘路径
        String parent = session.getServletContext().getRealPath("upload");
        // 保存头像文件的文件夹
        File dir = new File(parent);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //获取到这个文件名称,UUID工具来将生成一个新的字符串作为文件名
        //例如:avatar01.png
        // 保存的头像文件的文件名
        String suffix = "";
        String originalFilename = file.getOriginalFilename();
        int beginIndex = originalFilename.lastIndexOf(".");
        if (beginIndex > 0) {
            suffix = originalFilename.substring(beginIndex);
        }
        String filename = UUID.randomUUID().toString() + suffix;
        // 创建文件对象,表示保存的头像文件
        File dest = new File(dir, filename);//是一个空文件
        // 执行保存头像文件
        try {
            file.transferTo(dest);//将file文件中的数据写入到dest文件中
        } catch (IllegalStateException e) {
            // 抛出异常
            throw new FileStateException("文件状态异常,可能文件已被移动或删除");
        } catch (IOException e) {
            // 抛出异常
            throw new FileUploadIOException("上传文件时读写错误,请稍后重尝试");
        }
        // 返回头像路径/upload/test.png
        String avatar = "/upload/" + filename;
        // 从Session中获取uid和username
        Integer uid = getuidFromSession(session);
        String username = getUsernameFromSession(session);
        // 将头像写入到数据库中
        userService.changeAvatar(uid, avatar,username);
        // 返回成功头像路径给前端页面,将来用于头像展示使用
        return new JsonResult<String>(OK, avatar);
    }

UserController–changeAvatar


4. 上传头像-前端页面

在upload页面编写上传头像的代码

说明:如果直接使用表单进行文件的上传,需要给表单显示的添加一个属性
enctype="multipart/from-data"声明出来,
不会将目标文件的数据结构做修改在上传,不同于字符串

upload

    <script type="text/javascript">
      //cookie获取头像
      $(document).ready(function () {
        console.log("cookie中的avatar=" + $.cookie("avatar"));
        //将cookie值获取处理设置到头像的src属性上
        $("#img-avatar").attr("src", $.cookie("avatar"));
      });
      $("#btn-change-avatar").click(function() {
        $.ajax({
          url: "/users/change_avatar",
          type: "POST",
          data: new FormData($("#form-change-avatar")[0]),
          dataType: "JSON",
          processData: false, // processData处理数据
          contentType: false, // contentType发送数据的格式
          success: function(json) {
            if (json.state == 200) {
              alert("头像修改成功")
              //将服务器返回的头像地址设置img标签的src属性上
              //attr(属性,属性值):给某个属性设置某个值
              $("#img-avatar").attr("src", json.data);
              //显示最新头像
              $.cookie("avatar", json.data, {expires: 7});
            } else {
              alert("修改失败!" + json.message);
            }
          },
          error: function(xhr) {
            alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
            location.href = "login.html";
          }
        });
      });
    </script>

5.解决Bug

5.1 更默认的大小限制

SpringMVC默认为1MB文件进行上传,手动去修改SpringMVC默认上传文件的大小。

方式1:直接在配置文件中进行配置

#上传文件默认大小
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=15MB

方式2:需要采用Java代码的形式来设置文件的上传大小的限制。主类中进行配置,可以定义一个方法,必须使用@Bean修饰。在类的前面添加一个@Configuration注解进行修改类。MultipartConfigElement类型。

   @Bean
    public MultipartConfigElement getMultipartConfigElement() {
        //创建一个配置的工厂类对象
        MultipartConfigFactory factory = new MultipartConfigFactory();
        // DataSize dataSize = DataSize.ofMegabytes(10);
        // 设置文件最大10M,DataUnit提供5中类型B,KB,MB,GB,TB
        factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
        // 设置总上传数据总大小10M
        factory.setMaxRequestSize(DataSize.of(15, DataUnit.MEGABYTES));
        // 通过工厂类来创建MultipartConfigElement对象
        return factory.createMultipartConfig();
    }

application–优化


5.2 显示头像

在页面中提供ajax请求来提交文件,提交完成后返回了JSON串,解析出data中数据,设置的img头像标签的src属性。

  • serialize(): 可以将表单数据自动拼接成key=value的结构进行提交给服务器,一般提交是普通的控件类型中的数据(text\password\radio\checkbook)等等
  • FormData类:将表单中的数据保持原有的结构进行数据的提交。
new FormData($("#form")[0]);//文件类型的数据可以使用FormData对象进行存储
  • ajax默认处理数据时按照字符串的形式进行处理,以及默认会采用字符串的形式进行提交数据。关闭这两个默认的功能。
processData: false, // processData处理数据的形式,关闭默认形式
contentType: false, // contentType提交数据的格式,关闭默认形式

5.3 登录后显示头像

可以在更新头像成功后,将服务器返回的头像路径保存在客户端cookie对象,然后每次检测到用户打开上传头像页面,在这个页面中通过ready()方法来自动检查去读取cookie中头像并到src属性上。
1.设置cookie中的值:

导入cookie.js文件

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

调用cookie方法

login.html

//$.cookie(key,valye,time);//单位:天
$.cookie("avatar", json.data.avatar, {expires: 7})

2.在upload.html页面先引入cookie.js文件

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

3.在upload.html页main通过ready()自动读取cookie中的数据。

      //cookie获取头像
      $(document).ready(function () {
        console.log("cookie中的avatar=" + $.cookie("avatar"));
        //将cookie值获取处理设置到头像的src属性上
        $("#img-avatar").attr("src", $.cookie("avatar"));
      });

5.4 显示最新头像

在更改完头像后,将最新的头像地址,再一次保存到cookie,同名保存会覆盖原有cookie的值。

              //显示最新头像
              $.cookie("avatar", json.data, {expires: 7});

upload.html


测试


READ–上传头像

相关文章
|
1天前
|
人工智能 自然语言处理 JavaScript
2026年Windows+Ollama本地部署OpenClaw保姆级教程:本地AI Agent+阿里云上快速搭建
2026年OpenClaw凭借本地部署、私有化运行的特性,成为打造个人智能体的核心工具,而Ollama作为轻量级本地大模型管理工具,能让OpenClaw摆脱对云端大模型的依赖,实现**本地推理、数据不泄露、全流程私有化**的智能体验。本文基于Windows 11系统,从硬件环境准备、Ollama安装与模型定制、OpenClaw部署配置、技能扩展到常见问题排查,打造保姆级本地部署教程,同时补充阿里云OpenClaw(Clawdbot)快速部署步骤,兼顾本地私有化需求与云端7×24小时运行需求,文中所有代码命令均可直接复制执行,确保零基础用户也能快速搭建属于自己的本地智能体。
2212 9
|
12天前
|
人工智能 自然语言处理 监控
OpenClaw skills重构量化交易逻辑:部署+AI全自动炒股指南(2026终极版)
2026年,AI Agent领域最震撼的突破来自OpenClaw(原Clawdbot)——这个能自主规划、执行任务的智能体,用50美元启动资金创造了48小时滚雪球至2980美元的奇迹,收益率高达5860%。其核心逻辑堪称教科书级:每10分钟扫描Polymarket近千个预测市场,借助Claude API深度推理,交叉验证NOAA天气数据、体育伤病报告、加密货币链上情绪等多维度信息,捕捉8%以上的定价偏差,再通过凯利准则将单仓位严格控制在总资金6%以内,实现低风险高频套利。
6040 55
|
7天前
|
存储 人工智能 负载均衡
阿里云OpenClaw多Agent实战宝典:从极速部署到AI团队搭建,一个人=一支高效军团
在AI自动化时代,单一Agent的“全能模式”早已无法满足复杂任务需求——记忆臃肿导致响应迟缓、上下文污染引发逻辑冲突、无关信息加载造成Token浪费,这些痛点让OpenClaw的潜力大打折扣。而多Agent架构的出现,彻底改变了这一现状:通过“单Gateway+多分身”模式,让一个Bot在不同场景下切换独立“大脑”,如同组建一支分工明确的AI团队,实现创意、写作、编码、数据分析等任务的高效协同。
2528 27
|
29天前
|
人工智能 自然语言处理 Shell
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
42095 157
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
|
4天前
|
人工智能 JavaScript API
2026年Windows系统本地部署OpenClaw指南:附阿里云简易部署OpenClaw方案,零技术基础也能玩转AI助手
在AI办公自动化全面普及的2026年,OpenClaw(原Clawdbot、Moltbot)凭借“自然语言指令操控、多任务自动化执行、多工具无缝集成”的核心优势,成为个人与轻量办公群体打造专属AI助手的首选。它彻底打破了传统AI“只会对话不会执行”的局限——“手”可读写本地文件、执行代码、操控命令行,“脚”能联网搜索、访问网页并分析内容,“大脑”则可灵活接入通义千问、OpenAI等云端API,或利用本地GPU运行模型,真正实现“聊天框里办大事”。
903 2
|
1天前
|
人工智能 JSON JavaScript
手把手教你用 OpenClaw + 飞书,打造专属 AI 机器人
手把手教你用 OpenClaw(v2026.2.22-2)+ 飞书,10分钟零代码搭建专属AI机器人!内置飞书插件,无需额外安装;支持Claude等主流模型,命令行一键配置。告别复杂开发,像聊同事一样自然对话。
870 5
手把手教你用 OpenClaw + 飞书,打造专属 AI 机器人
|
7天前
|
人工智能 自然语言处理 安全
2026年OpenClaw Skills安装指南:Top20必装清单+阿里云上部署实操(附代码命令)
OpenClaw(原Clawdbot)的强大之处,不仅在于其开源免费的AI执行引擎核心,更在于其庞大的Skills生态——截至2026年2月,官方技能市场ClawHub已收录1700+各类技能插件,覆盖办公自动化、智能交互、生活服务等全场景。但对新手而言,面对海量技能往往无从下手,盲目安装不仅导致功能冗余,还可能引发权限冲突与安全风险。
1251 8
|
1天前
|
人工智能 运维 安全
OpenClaw极速部署:ZeroNews 远程管理OpenClaw Gateway Dashboard指南+常见错误解决
OpenClaw作为高性能AI智能体网关平台,其Gateway Dashboard是管理模型调用、渠道集成、技能插件的核心操作界面,但默认仅支持本地局域网访问。官方推荐的Tailscale、VPN等远程访问方案在国内网络环境中体验不佳,而ZeroNews凭借轻量化部署、专属域名映射、多重安全防护的特性,成为适配国内网络的最优远程管理解决方案。
776 2