• 头像上传功能


    头像上传

    A> MultipartFile接口

    MultipartFile接口常用的的API见下表:

    方法功能描述
    String getOriginalFilename()获取上传文件的原始文件名,即该文件在客户端中的文件名
    boolean isEmpty()判断上传的文件是否为空,当没有选择文件就直接上传,或者选中的文件是0字节的空文件时,返回true,否则返回false
    long getSize()获取上传的文件大小,以字节为单位
    String getContentType()根据所上传的文件的扩展名决定该文件的MIME类型,例如上传.jpg格式的图片,将返回image/jpeg
    InputStream getInputStream()获取上传文件的输入字节流,通常用于自定义读取所上传的文件的过程,该方法与transferTo()方法不可以同时使用
    void transferTo(File dest)保存上传的文件,该方法与getInputStream()方法不可以同时使用

    B> MultipartResolver接口

    1.MultipartResolver可以将上传过程中产生的数据封装为MultipartFile类型的对象中。

    2.在配置MultipartResovler时,可以为其中的几个属性注入值:

    • maxUploadSize:上传文件的最大大小,假设设置值为10M,一次性上传5个文件,则5个文件的大小总和不允许超过10M。
    • maxUploadSizePerFile:每个上传文件的最大大小,假设设置值为10M,一次性上传5个文件,则每个文件的大小都不可以超过10M,但是5个文件的大小总和可以接近50M。
    • defaultEncoding:默认编码。

    C> 基于SpringMVC的文件上传案例

    3.1 创建项目

    1.创建Java Enterprise项目,设置Name为springmvc-upload,Group为com.cy,Artifact为controller的Java企业级项目。

    2.将项目com.cy.controller包下自动生成的HelloServlet类删除,并删除webapp下自动生成的index.jsp文件。

    3.添加文件上传jar包依赖(关于文件上传需要添加spring-webmvc和commons-fileupload依赖)。

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>4.3.6.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>commons-fileuploadgroupId>
            <artifactId>commons-fileuploadartifactId>
            <version>1.4version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.在src\main\resources文件夹下创建spring配置文件,并将文件命名为spring-upload.xml。

    
    <beans xmlns="http://www.springframework.org/schema/beans"
    	   xmlns:context="http://www.springframework.org/schema/context"
    	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	   xsi:schemaLocation="http://www.springframework.org/schema/beans
    	   http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    	   http://www.springframework.org/schema/context
    	   http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    	
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.2 前端页面设计

    在webapp目录下创建upload.html页面,并在页面中添加如下代码。

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>文件上传title>
    head>
    <body>
        <h3>文件上传h3>
        
        <form action="upload.do" method="post" enctype="multipart/form-data">
            <table border="1" cellspacing="0" cellpadding="0">
                <tr>
                    <td>文件名(N):td>
                    <td><p><input type="file" name="file"/>p>td>
                tr>
                <tr>
                    <td colspan="2" align="center"><input type="submit" name="上传"/>td>
                tr>
            table>
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    注意:form表单的请求方式必须设置为POST,并配置属性enctype=“multipart/form-data”,文件上传input控件的name属性值需设置为file值。

    3.3 后台功能实现

    1.在web.xml文件中配置前端控制器和过滤器,并指定DispatcherServlet加载的配置文件springmvc-upload.xml的位置。

    <servlet>
        <servlet-name>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc-upload.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>*.dourl-pattern>
    servlet-mapping>
    
    <filter>
        <filter-name>CharacterEncodingFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>utf-8param-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2.创建com.cy.controller.UploadController控制器类,在类的声明之前添加@Controller注解,并在控制器中添加处理请求的upload()方法,为此方法添加类型为MultipartFile接口的参数,并为该参数添加@RequestParam注解,表示客户端上传的文件。

    package com.cy.controller;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.io.IOException;
    import java.util.UUID;
    
    @Controller
    public class UploadController {
        /*
        @RequestMapping("upload.do")
        @ResponseBody
        public String upload(@RequestParam("file") MultipartFile file) {
            System.out.println("UploadController.upload()...");
            File dest = new File("D:/1.png");
            try {
                // 调用MultipartFile参数对象的transferTo()方法即可保存上传的文件
                file.transferTo(dest);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "OK";
        }
        */
        
        @RequestMapping("upload.do")
        @ResponseBody
        public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile file) throws IOException {
            // 获取上传文件的原始文件名
            String originalFilename = file.getOriginalFilename();
            // 获取上下文的绝对路径
            String realPath = request.getServletContext().getRealPath("upload");
            System.out.println(realPath);
            // 创建File文件对象
            File dir = new File(realPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            // 自定义上传文件名
            String fileName = UUID.randomUUID().toString();
            // 获取上传文件扩展名
            String suffix = "";
            int beginIndex = originalFilename.lastIndexOf(".");
            if (beginIndex > 0) {
                suffix = originalFilename.substring(beginIndex);
            }
            String fullFilename = fileName + suffix;
            // 调用MultipartFile参数对象的transferTo()方法即可保存上传的文件
            file.transferTo(new File(dir, fullFilename));
    
            return "OK";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    3.在springmvc-upload.xml配置文件中添加组件扫描和CommonsMultipartResolver类的bean标签配置。

    
    <context:component-scan base-package="com.cy" />
    
    
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:CommonsMultipartResolver类在配置时,id值必须设置成multipartResolver。

    4.启动项目,访问http://localhost:8080/springmvc_upload_war_exploded/upload.html网址测试文件提交。

    1.上传头像-持久层

    将对象文件存在操作系统上,然后在把这个文件路径给记录下来,因为在记录路径是非常便捷和方便,将如果要打开文件可以依据这个路径支找到这个文件,在数据中需要保存这个 文件的路径即可,一般情况下将静态资源(图片,文件,其他资源文件)放在某台单独的服务器上

    1.1SQL语句的规划

    1.根据uid查询用户的数据,在上传头像之前,首先要保证当前这个用户的数据存在,检测是否被标记为已经删除,检测输入的原始密码是否正确

    select * from t_user where uid = #{uid}
    
    • 1

    2.上传头像其他就是相关于修改用户的avatar字段,所以sql语句是

    update t_user set avatar = #{avatar} ,
    				  modified_user = #{modifiedUser},
    				  modified_tiem = #{modifiedTiem}
    			  where uid = #{uid}
    
    • 1
    • 2
    • 3
    • 4

    1.2设计接口和抽象方法

    由于UserMapper接口已经定义过,所以直接定义抽象方法即可

    /**
     * 用户模块的持久层接口
     */
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
    
    
        /**
         * 根据uid修改用户头像
         * @param uid 用户uid
         * @param avatar 头像路径
         * @param modifiedUser 修改者
         * @param modifiedTime 修改时间
         * @return 受影响行数,如果返回1修改成功,返回0修改失败
         */
        Integer updateAvatarByUid(@Param("uid")Integer uid,
                                  @Param("avatar")String avatar,
                                  @Param("modifiedUser")String modifiedUser,
                                  @Param("modifiedTime")Date modifiedTime);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1.3编写映射文件UserMapper.xml

    <!--    
    
        根据uid修改用户信息
        Integer updateAvatarByUid(@Param("uid")Integer uid,
                                  @Param("avatar")String avatar,
                                  @Param("modifiedUser")String modifiedUser,
                                  @Param("modifiedTime")Date modifiedTime);
    
    -->
        <update id="updateAvatarByUid">
            update t_user set 
                             avatar = #{avatar},
                             modified_user = #{modifiedUser},
                             modified_time = #{modifiedTime}
                           where uid = #{uid}
        </update>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.4 测试

        //上传头像
        @Test
        void updateAvatarByUidTest(){
            Integer integer = userMapper.updateAvatarByUid(1, "eejeqepcwqin1314168520521", "邓宇瑞", new Date());
            if (integer==0){
                System.out.println("上传头像失败!");
            }else {
                System.out.println("上传头像成功!");
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.上传头像-业务层

    2.1 规划异常

    1.由于上传前需要先查询该用户是否存在,同时还可以防止用户过长时间不操作,如果不存在直接抛出UserNotFoundException

    2.上传头像可以出现上传失败,如果出现上传失败直接抛出updateException异常

    综上:对于这个两种可能出现的异常都已经定义过,所以不需要重新定义

    2.2 设计接口和抽象方法

    业务层的设计需要参考Mapper层,由于Mapper层需要四个参数,并且第四个参数是当前时间Date,所以这个参数可以直接在业务创建出来。

    //处理用户注册
    public interface IUserService {
    
        /**
         * 根据用户uid修改用户头像【其实就是上传头像】
         * @param uid 用户uid
         * @param username 用户名【也是修改者】
         * @param avatar 头像路径
         * @return 如果返回1说明修改成功,返回0说明修改失败
         */
        void changeAvatar(Integer uid,String username,String avatar);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3 实现抽象方法

    //用户模块业务层的实现类
    @Service
    public class UserServiceImpl implements IUserService {
    
        @Autowired
        private UserMapper userMapper;
    
    
        // 根据用户uid修改头像【其实就是上传头像】
        @Override
        public void changeAvatar(Integer uid, String username, String avatar) {
            // 第一步:先查询该用户是否存在,根据uid查询
            User user = userMapper.findByUid(uid);
            // 第二步:判断该用户是否为null或isDelete等于1,如果为null或等于1说明该用户不存在,否则存在
            if (user==null || user.getIsDelete()==1){
                throw new UserNotFoundException("该用户不存在!");
            }
            
    
            // 第三步:调用上传头像方法
            Integer result = userMapper.updateAvatarByUid(uid, avatar, username, new Date());
    
            // 第五步:判断返回值
            if (result==0){
                throw new UpdateException("上传头像时出现未知异常!");
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.4 测试

        // 根据uid上传图像
        @Test
        void changeAvatarTest(){
            try {
                userService.changeAvatar(1,"明天","明天131488168");
                System.out.println("上传成功!");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
                System.out.println("上传失败");
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.上传头像-控制层

    3.1 处理异常

    文件异常父类:
    	FileUploadException 泛指文件上传的异常(父类)继承于RuntimeException
    	
    父类是:FileUploadException
    		FileEmptyException  	文件为空的异常
    		FileSizeException		文件大小超出限制异常
    		FileTypeException		文件类型异常
    		FileUploadIoException	文件读写的异常
    		FileStateException		文件状态的异常
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.在处理上传文件的过程中,用户可能会选择错误的文件上传,此时就应该抛出对应的异常并进行处理。所以需要创建文件上传相关异常的基类,即在com.haikang.store.controller.ex包下创建FileUploadException类,并继承自RuntimeException类。

    /** 文件上传相关异常的基类 */
    public class FileUploadException extends RuntimeException {
        public FileUploadException() {
            super();
        }
    
        public FileUploadException(String message) {
            super(message);
        }
    
        public FileUploadException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public FileUploadException(Throwable cause) {
            super(cause);
        }
    
        protected FileUploadException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.在处理上传的文件过程中,经分析可能会产生以下异常。这些异常类都需要继承自FileUploadException类。

    // 上传的文件为空
    FileEmptyException
    // 上传的文件大小超出了限制值
    FileSizeException
    // 上传的文件类型超出了限制
    FileTypeException
    // 上传的文件状态异常
    FileStateException
    // 上传文件时读写异常
    FileUploadIOException
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.创建FileEmptyException异常类,并继承FileUploadException类。

    /** 上传的文件为空的异常,例如没有选择上传的文件就提交了表单,或选择的文件是0字节的空文件 */
    public class FileEmptyException extends FileUploadException {
        // Override Methods...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.创建FileSizeException异常类,并继承FileUploadException类。

    /** 上传的文件的大小超出了限制值 */
    public class FileSizeException extends FileUploadException {
        // Override Methods...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.创建FileTypeException异常类,并继承FileUploadException类。

    /** 上传的文件类型超出了限制 */
    public class FileTypeException extends FileUploadException {
        // Override Methods...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.创建FileStateException异常类,并继承FileUploadException类。

    /** 上传的文件状态异常 */
    public class FileStateException extends FileUploadException {
        // Override Methods...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.创建FileUploadIOException异常类,并继承FileUploadException类。

    /** 上传文件时读写异常 */
    public class FileUploadIOException extends FileUploadException {
        // Override Methods...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8.在控制器的基类中处理异常

    // 控制器类的基类,用于处理异常
    @ControllerAdvice
    public class BaseController {
        // 操作成功的状态码:
        public final static int ok = 200;
    
            @ExceptionHandler({ServiceException.class,FileUploadException.class})//表示Service业务层,出现的异常会跳转到该控制器中统一处理
        public JsonResult<Void> handleException(Throwable e){
            JsonResult<Void> result = new JsonResult<>();
            
            // 文件为空异常
           if (e instanceof FileEmptyException){
                result.setState(6001);
                result.setMessage(e.getMessage());
            // 文件大小异常
            }else if (e instanceof FileSizeException){
                result.setState(6002);
                result.setMessage(e.getMessage());
            // 文件状态异常
            }else if (e instanceof FileStateException){
                result.setState(6003);
                result.setMessage(e.getMessage());
            // 文件类型异常
            }else if (e instanceof FileTypeException){
                result.setState(6004);
                result.setMessage(e.getMessage());
            // 文件上传时出现异常
            }else if (e instanceof FileUploadIoException){
                result.setState(6005);
                result.setMessage(e.getMessage());
            }
    
            return result;
        }
        
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    注意是:必须要在异常处理方法上添加FileUploadException.class表示也可以处理FileUploadException类型的异常

        @ExceptionHandler({ServiceException.class,FileUploadException.class})//表示Service业务层,出现的异常会跳转到该控制器中统一处理
    
    
    • 1
    • 2

    3.2 设计请求

    请求路径  url: "http://localhost/users/change_avatar"
    请求参数  data: MultipartFile file,HttpSession session
    请求类型  type: POST
    响应结果  JsonResult
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.3 处理请求

    @RestController
    @RequestMapping("users")
    public class UserController extends BaseController{
    
        @Autowired
        IUserService userService;
    
        // 第一步:规定文件大小
        public static final int AVATAR_MAX_SIZE = 20 * 1024 * 1024;
    
        // 第二步:允许上传的头像的文件类型
        public static final List<String> AVATAR_TYPES = new ArrayList<>();
    
        // 第三步:初始化上传的文件类型
        static {
            AVATAR_TYPES.add("image/jpeg");
            AVATAR_TYPES.add("image/png");
            AVATAR_TYPES.add("image/bmp");
            AVATAR_TYPES.add("image/gif");
        }
    
        /**
         * 文件上传功能
         * @param session session对象用于获取用户uid和username
         * @param file 文件
         * @return 响应文件路径和状态
         *
         * MultipartFile接口是SpringMVC提供一个接口,这个 接口为我们包装了
         * 获取文件类型的数据(任何类型的file文件都可以接收),SpringBoot它有整合了
         * SpringMVC,只需要在处理请求的方法参数列表上声明一个参数为MultipartFiler的参数,然后
         * SpringBoot自动将传递给文件数据赋值给这个参数
         */
        @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){
                throw new FileSizeException("不允许上传文件大小超过"+(AVATAR_MAX_SIZE/1024)+"KB的头像文件!");
            }
    
            // 判断上传文件的类型是否正确
            // 1.获取文件类型
            String fileContentType = file.getContentType();
            // 2.如果不包含,直接抛出异常
            if (!AVATAR_TYPES.contains(fileContentType)){
                throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:\n" + AVATAR_TYPES);
            }
    
    
            // 获取当前项目的绝对磁盘路径
            String parent = session.getServletContext().getRealPath("upload");
    
            // 判断保存头像文件的文件夹是否存在,如果不存在则创建
            File dir = new File(parent);
            if (!dir.exists()){
                // 创建upload文件夹
                dir.mkdirs();
            }
    
            // 保存头像文件的文件名
            // 返回文件名:例如:eeje.jpg[包含文件类型就是`.jpg`]
            String originalFilename = file.getOriginalFilename();
            // 获取文件后缀,就是获取最后一个`.` 的索引,开始截取
            int lastIndexOf = originalFilename.lastIndexOf(".");
            // 截取出后缀 例如:.jpg
            String suffix = originalFilename.substring(lastIndexOf);
    
            // 拼接出随机文件名,防止文件名重复
            String fileName = UUID.randomUUID().toString()+suffix;
    
            // 创建文件对象,表示保存的头像文件
            File dest = new File(dir,fileName);
            // 执行保存头像文件
            try {
                file.transferTo(dest);
            }catch (FileStateException e){
                throw new FileStateException("文件状态异常,可能文件已经被移动或删除!");
            } catch (IOException e) {
                throw new FileUploadIoException("上传文件时读写错误,请稍后重尝试!");
            }
    
    
            // 执行UserService文件保存头像路径
            // 头像路径
            String avatar = "/upload/"+fileName;// 注意是:一定不能少掉`/`,该表示当前项目的根路径
            // 从Session中获取uid和username
            Integer uid = getUidFromSession(session);
            String username = getUserNameFromSession(session);
            // 将头像写入到数据库中
            userService.changeAvatar(uid,username,avatar);
    
            // 返回成功头像路径
            return new JsonResult<>(ok,avatar);
        }
       
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    4.上传头像-页面

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

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

    在这里插入图片描述

    					<form class="form-horizontal" 
    							  action="/users/change_avatar"
    							  method="post"
    							  enctype="multipart/form-data"
    							  role="form">
    							<div class="form-group">
    								<label class="col-md-2 control-label">选择头像:</label>
    								<div class="col-md-5">
    									<img id="img-avatar" src="../images/index/user.jpg" class="img-responsive" />
    								</div>
    								<div class="clearfix"></div>
    								<div class="col-md-offset-2 col-md-4">
    									<input type="file" name="file">
    								</div>
    							</div>
    							<div class="form-group">
    								<div class="col-sm-offset-2 col-sm-10">
    									<input type="submit" class="btn btn-primary" value="上传" />
    								</div>
    							</div>
    						</form>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    表单必须满足下面三个属性

    <form class="form-horizontal" 
            action="/users/change_avatar"
            method="post"
            enctype="multipart/form-data"
            role="form">
    </form>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    用户-上传头像-设置上传文件大小

    1.在SpringBoot中默认MultipartResolver的最大文件大小值为1M。如果上传的文件超过1M,会就抛出FileSizeLimitExceededException异常

    在这里插入图片描述

    解析方式一:使用Java代码的方式

    如果在需要调整上传的限制值,直接在主启动类中添加getMultipartConfigElement()方法,并且使用@Bean标记.

    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
    public class StoreApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(StoreApplication.class, args);
        }
        
        
        @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));
            factory.setMaxRequestSize(DataSize.of(10, DataUnit.MEGABYTES));
            // 设置总上传数据总大小10M
            return factory.createMultipartConfig();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    解析方式二:使用配置文件方式

    yaml方式:

    spring:
      servlet:
        multipart:
          max-file-size: 20MB #上传文件的最大大小
          max-request-size: 25MB #最大请求大小
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    properties方式:

    #方式1
    spring.servlet.multipart.max-file-size=10MB
    spring.servlet.multipart.max-request-size=10MB
    #方式2
    spring.servlet.multipart.maxFileSize=10MB
    spring.servlet.multipart.maxRequestSize=10MB
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    回显头像

    注意是:在ajax请求中具有自动提交的功能,所以在使用ajax发送请求时,需要将

    在页面中通过ajax请求来提交文件,提交完成后返回json字符串,解析出data中数据,设置到img头像标签的src属性上就可以了:

    • serialize():可以将表单数据自动拼接成key=value的结构进行提交给服务器,一般提交是普通的控件类型中的数据,如text \ password \ radio \ checkbox

    • FormData类:将表单中的数据保持原有的结构进行数据提交

    • 如:
      new FormData($("#form")[0]); // 文件类型的数据可以使用`FormData`对象进行存储,注意是:`FormData($("#form")[0])`表示是第一个控件
      
      
      • 1
      • 2
      • 3
    • ajax默认处理数据时按照字符串形式处理,以及默认会采用字符串形式进行提交数据,关闭这两个默认功能

    • processData: false, // processData处理数据 , 关闭处理数据
      contentType: false, // contentType发送数据格式 ,关闭默认提交数据的形式
      
      
      • 1
      • 2
      • 3

    总结:在JQuery

    val方法是:可以获取到文本的值,并且可以修改文件中的值,如:修改组件中的文件值

    attrprop区别?
    1.如果操作的是元素的固有属性,则建议使用prop【就是系统定义的属性】
    2.如果操作的是元素自定义的属性,则建议使用attr

    1.修改表单中提交组件按钮

    						
    						<form class="form-horizontal"
    							  id="form-change-avatar"
    							  action="/users/change_avatar"
    							  method="post"
    							  enctype="multipart/form-data"
    							  role="form">
    							<div class="form-group">
    								<label class="col-md-2 control-label">选择头像:label>
    								<div class="col-md-5">
    									<img id="img-avatar" src="../images/index/user.jpg" class="img-responsive" />
    								div>
    								<div class="clearfix">div>
    								<div class="col-md-offset-2 col-md-4">
    									<input type="file" name="file">
    								div>
    							div>
    							<div class="form-group">
    								<div class="col-sm-offset-2 col-sm-10">
    									<input type="button" id="btn-change-avatar" class="btn btn-primary" value="上传" />
    								div>
    							div>
    						form>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.发送ajax请求

    		<!--页脚结束-->
    		<script type="text/javascript">
    			$("#btn-change-avatar").click(function () {
    				$.ajax({
    					url: "http://localhost/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-avatar").attr("src",json.data);
    						}else {
    							alert("修改失败!")
    						}
    					},
    					error: function (xhr) {
    						alert(xhr.status+"-----"+xhr.message);
    					}
    				});
    			});
    		</script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    回显头像总结:

    上传后显示头像

    1.头像上传成功后,显示上传的头像。在upload.html页面中,是使用img标签来显示头像图片的。首先确定img标签是否添加有id="img-avatar"属性,便于后续访问该标签;而img标签是通过src属性来决定显示哪张图片的,所以修改src该属性的值即可设置需要显示的图片。修改表单添加id="form-change-avatar"属性。修改input标签,添加id="btn-change-avatar"和type="button"属性。

    在这里插入图片描述

    2.在upload.html页面中body标签内部的最后,添加script标签用于编写JavaScript程序。

    • processData:处理数据。默认情况下,processData的值是true,其代表以对象的形式上传的数据都会被转换为字符串的形式上传。而当上传文件的时候,则不需要把其转换为字符串,因此要改成false。
    • contentType:发送数据的格式。其代表的是前端发送数据的格式,默认值application/x-www-form-urlencoded。代表的是ajax的 data是以字符串的形式传递,使用这种传数据的格式,无法传输复杂的数据,比如多维数组、文件等。把contentType设置为false就会改掉之前默认的数据格式,在上传文件时就不会报错。
    <script type="text/javascript">
        $("#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) {
                        $("#img-avatar").attr("src", json.data);
                    } else {
                        alert("修改失败!" + json.message);
                    }
                },
                error: function(xhr) {
                    alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
                    location.href = "login.html";
                }
            });
    	});
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.完成后启动项目,打开浏览器先登录,再访问http://localhost:80/web/upload.html进行测试。

    登录后显示头像【重点】

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

    在页面中设置cookie步骤:

    第一步:导入cookie.js文件

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

    第二步:调用cookie方法:

    $.cookie(key,value,time); // time单位为:天
    
    
    • 1
    • 2

    登录后显示图片步骤:

    第一步:导入cookie.js文件

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

    第二步:在login.html页面设置cookie的值

    		<!--页脚结束-->
    	<script type="text/javascript">
    		// 第一步:监听按钮
    		$("#btn-login").click(function () {
    			$.ajax({
    				url: "http://localhost:80/users/login",
    				type: "POST",
    				dataType: "JSON",
    				data: $("#form-login").serialize(),
    				success: function (json) {
    					if (json.state == 200){
    						alert("登录成功!");
    					}
    					// 将服务器返回头像设置到cookie中
    					$.cookie("avatar",json.data.avatar,{expires: 7}); // 表示将cookie存活时间设置为7天
    					location.href = "http://localhost:80/web/index.html";
    				},
    				error: function (xhr) {
    					alert("登录失败!"+xhr.status);
    				}
    			});
    		});
    	</script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    第三步:在upload.html页面,导入cookie.js文件

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

    第四步:在upload.html页面,调用ready()方法自动读取cookie中的值

    		<!--页脚结束-->
    	<script type="text/javascript">
    		
    		// 调用 ready 方法读取cookie的值
    		$(document).ready(function () {
    			let avatar = $.cookie("avatar");
    			// 将cookie值获取出来设置到头像src属性中
    			$("#img-avatar").attr("src", $.cookie("avatar"));
    		});
    	</script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    显示最新的头像:

    在更新头像后,将最新的头像地址,再次保存到cookie中,同名保存会覆盖原来的cookie

    		<!--页脚结束-->
    	<script type="text/javascript">
    		
    		// 调用 ready 方法读取cookie的值
    		$(document).ready(function () {
    			let avatar = $.cookie("avatar");
    			// 将cookie值获取出来设置到头像src属性中
    			$("#img-avatar").attr("src", $.cookie("avatar"));
    		});
    		
    		// 第一步:监听按钮
    		$("#btn-login").click(function () {
    			$.ajax({
    				url: "http://localhost:80/users/login",
    				type: "POST",
    				dataType: "JSON",
    				data: $("#form-login").serialize(),
    				success: function (json) {
    					if (json.state == 200){
    						alert("登录成功!");
    					}
    					// 将服务器返回头像设置到cookie中,如果重新上传了新头像,则将新的头像`路径`保存到cookie中
    					$.cookie("avatar",json.data.avatar,{expires: 7}); // 表示将cookie存活时间设置为7天
    					location.href = "http://localhost:80/web/index.html";
    				},
    				error: function (xhr) {
    					alert("登录失败!"+xhr.status);
    				}
    			});
    		});
    	</script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    总结:

    登录显示头像

    1.首先检查登录成功后是否返回了头像的数据。访问http://localhost:8080/users/login?username=admin&password=321测试。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-clIkmX4O-1659694981318)(D:\typora笔记\电脑商城\img\1659280116607.png)]

    2.用户名、用户Id、用户头像等数据,属于常用数据,在客户端的许多页面都可能需要使用,如果每次都向服务器提交请求获取这些数据,是非常不合适的。可以在用户登录成功后,将这些数据存储在客户端本地,后续在客户端中需要显示这些数据时,直接从本地获取即可,无需再向服务器请求这些数据。在客户端本地存取数据时,可以使用Cookie技术。

    3.设计思路:当用户登录成功后,将服务器返回的头像路径存储到本地的Cookie中,在打开“上传头像”页面时,从本地的Cookie中读取头像路径并显示即可。在登录login.html页面中,当登录成功后,将用户头像路径保存到Cookie中。

    $("#btn-login").click(function() {
        $.ajax({
            url: "/users/login",
            type: "POST",
            data: $("#form-login").serialize(),
            dataType: "json",
            success: function(json) {
                if (json.state == 200) {
                    alert("登录成功!");
                    $.cookie("avatar", json.data.avatar, {expires: 7});
                    console.log("cookie中的avatar=" + $.cookie("avatar"));
                    location.href = "index.html";
                } else {
                    alert("登录失败!" + json.message);
                }
            }
        });
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    语法:$.cookie(名称,值,[option])。[option]参数说明:

    expires:有限日期,可以是一个整数或一个日期(单位天)。如果不设置这个值,默认情况下浏览器关闭之后此Cookie就会失效。

    path:表示Cookie值保存的路径,默认与创建页路径一致。

    domin:表示Cookie域名属性,默认与创建页域名一样。要注意跨域的概念,如果要主域名二级域名有效则要设置“.xxx.com”。

    secrue:布尔类型的值,表示传输Cookie值时,是否需要一个安全协议。

    4.在upload.html页面中,默认并没有引用jqueyr.cookie.js文件,因此无法识别$.cookie()函数;所以需要在upload.html页面head标签内添加jqueyr.cookie.js文件。

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

    5.在打开页面时自动读取显示用户图像。获取Cookie中头像的路径,然后将获取到的头像路径设置给img标签的src属性以显示头像。在upload.html页面中的script标签的内部添加自动读取用户图像的jquery代码。

    $(document).ready(function () {
        console.log("cookie中的avatar=" + $.cookie("avatar"));
        $("#img-avatar").attr("src", $.cookie("avatar"));
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    显示最新头像

    以上代码表示“每次打开页面时,读取Cookie中的头像并显示”,如果此时重新上传用户头像,而Cookie中所保存的头像还是之前上传的头像路径值,无法显示最新的用户头像。所以当用户重新上传头像后,还应把新头像的路径更新到Cookie中。

    1.在upload.html页面中,用户头像修改成功后,并将新的用户头像路径保存到Cookie中。

    $.cookie("avatar", json.data, {expires: 7});
    
    
    • 1
    • 2

    在这里插入图片描述

    2.完成后启动项目,打开浏览器先登录,再访问http://localhost:8080/web/upload.html进行测试。

  • 相关阅读:
    MacBook当作Win电脑副屏
    103.(cesium之家)cesium蜂巢图(正方形)
    程序员是如何看待“祖传代码”的?
    Java- 继承 和 实现 、组合
    11.17 知识总结(事务、常见的字段类型等)
    [免费专栏] Android安全之动态代码注入技术(利用JDB调试APK)
    在C++中++a和a++有什么区别?
    如何实现前后端交互
    设计模式之单例模式
    C++-Cmake指令:file【文件操作命令】【比如:file GLOB命令主要用于匹配规则在指定的目录内匹配到所需要的文件】
  • 原文地址:https://blog.csdn.net/weixin_47267628/article/details/126183403