Spring MVC 学习笔记(4) --- [SpringMVC的文件上传与拦截器,以及更新登录用户头像的简易案例]

紧接之前的笔记 --> springmvc学习笔记3(,AJAX交互请求,JSON格式响应;中文乱码配置)


1.文件上传

需要借助文件上传的工具包;
在maven引入资源即可

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>

还需要在xml配置文件中配置springmvc的相关配置;
文件解析器;这里设置最大上传量为10M;

<!--文件解析器,这里配置最大上传大小为10m-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8"></property>
    <property name="maxUploadSize" value="10485760"></property>
</bean>

在控制层的方法中使用方法参数类型CommonsMultipartFile即可接受文件

@RequestParam(“fileName”) CommonsMultipartFile file 接收文件;
file.getOriginalFilename();获得原始文件名
file.getContentType();获得文件类型
file.getInputStream();获得输入流对象

2.拦截器

之前分析过,SpringMVC 定义了拦截器接口 HandlerInterceptor;
会对配置的路径进行拦截处理;也可以配置不对某些指定的路径进行拦截;

在这里插入图片描述

再具体自定义使用时,定义一个类继承这个HandlerInterceptor接口,比较人性化的是,只需要重写需要的方法即可;而不是像之前那样需要将方法全部重写;

在这里插入图片描述

方法1:preHandle预处理方法;

实现处理器方法的预处理,就是在处理器方法执行之前这个方法会被执行,相当于拦截了处理器方法,框架会传递请求和响应对象给该方法,第三个参数为被拦截的处理器方法。
preHandle 方法返回 true 表示继续流程(如调用下一个拦截器或处理器方法),
返回 false 表示流程中断,不会继续调用其他的拦截器或处理器方法,此时需要通过 response 来产生响应;

方法2:postHandle后处理方法;

实现处理器方法的后处理,就是在处理器方法调用完成,但在渲染视图之前,该方法被调用,
此时可通过 modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理。
目前不进行使用;

方法3:afterCompletion整个请求处理完毕,视图渲染完毕时该方法被执行。


例如简易拦截器的配置

//简易的登录拦截配置;
public class LoginInter implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        People people = (People) session.getAttribute("people");
        if(people==null){
            response.getWriter().print("202");
            return false;
        }else {
            return true;
        }
    }
}

另外仅实现接口还是不够的,需要去配置用哪个拦截器进行哪些拦截,
当然,这里不是在web,xml中进行配置;
spring-mvc.xml配置文件中进行配置;
一般使用<mvc:mapping path="/**"/>拦截所有请求路径;
当然,还要配置不拦截的请求<mvc:exclude-mapping path=""/>在path中填入即可;

例如对刚才的拦截器进行配置;

<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--匹配拦截所有路径-->
        <mvc:mapping path="/**"/>
        <!--选择不拦截什么路径-->
        <mvc:exclude-mapping path="/wantLogin/toLogin"/>
        <mvc:exclude-mapping path="/css/**"/>
        <mvc:exclude-mapping path="/js/**"/>
        <mvc:exclude-mapping path="/img/**"/>
        <mvc:exclude-mapping path="/**.html"/>
        <!--自定义的拦截器注入-->
        <bean id="LoginInter" class="com.xiaozhire0.ssm.utils.LoginInter"/>
    </mvc:interceptor>
</mvc:interceptors>

3.更新登录用户头像案例搭建;

将本机文件夹托管给tomcat使用;

由于是web项目,在项目启动后,访问到的图片其实已经不是本机上的文件夹了,而是访问部署的服务器;
所以首先要将使用的文件夹交给tomcat;
其实也可以在tomcat安装下的配置文件中进行设置,或者将文件夹放到tomcat安装下的webapps内;

但是IDEA设置的话比较方便,只需要一个小小的设置,就能将文件夹交给tomcat进行使用管理;

比如我一会就将这个文件夹xiaozhire0userimg作为用户上传头像的存储仓库;
一会就可使用 IP 端口/xiaozhire0userimg 访问到这个文件夹的内容;

在这里插入图片描述

具体的操作很便捷,直接在tomcat的配置处点击external Sources;配置托管的外部资源;

在这里插入图片描述

选择指定文件夹即可

在这里插入图片描述

先同意,查看无误后点击OK;

在这里插入图片描述

具体的搭建

(1)在上次登录案例的基础上进行初步修改

在上一篇笔记Spring MVC 学习笔记(3) — [SpringMVC的数据响应(Ajax提交请求后,用JSON格式响应数据)]
就做了基础的登录;

这里需要给之前的数据表t_spandmb中加入新的字段:
old_file_name旧文件名 new_file_name新文件名;
为了上传头像的搭建使用;

在这里插入图片描述

然后实体类People也修改一下,
加入新的属性oldFileName;newFileName;采用驼峰命名法,因为之前在mybatis的配置文件中已经设置开启了驼峰命名匹配;

/**
 * @author by CSDN@小智RE0
 * @date 2021-11-21 12:25
 * 人类;
 */
//将这个类注入到spring;
@Component
public class People {
    //这边的话,就保持和数据库的字段名一致吧;
    private Integer id;
    private String  name;
    private String  password;
    private Integer age;
    @DateTimeFormat(pattern = "YYYY-MM-dd")
    private Date    birthday;
    //旧文件名,新文件名;
    private String oldFileName;
    private String newFileName;

    public String getOldFileName() {
        return oldFileName;
    }

    public void setOldFileName(String oldFileName) {
        this.oldFileName = oldFileName;
    }

    public String getNewFileName() {
        return newFileName;
    }

    public void setNewFileName(String newFileName) {
        this.newFileName = newFileName;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

(2)分析流程;

  • 用户将图片上传过来,后台接收到文件后,需要在服务器的指定位置创建一个位置存放用户的头像;
    然后需要将该用户头像的文件名称存入数据库;
    当然这个可以自己规定头像名的具体格式,

  • 还要考虑到用户后来需要更新头像,数据库的文件名可能与仓库的头像文件名不一致,所以这个存入的数据需要跟随存入仓库的头像文件名一致;并且这个执行的SQL语句实际上是更新语句;根据用户的ID修改用户的信息;

  • 还有用户在访问服务器上的图片时,需要根据自己的信息找到属于自己的文件夹,找到其中的对应文件名;所以在之前创建用户的文件夹时不能将路径写死,要动态拼入用户的专属标记作为创建的文件夹名称;

  • 我这个是用户的头像更新案例,所以说要考虑到用户登陆进来的默认头像显示;
    最后还考虑到新用户登录进入时可能没有头像,我这里默认一个头像;就放在xiaozhire0userimg文件夹下的default文件夹内;默认让新用户的头像图片链接指向此处;

在这里插入图片描述


(3)在登录成功处进行上传头像,

这里弹出的模态框使用了bootstrap提供的组件;
还是比较方便的;
这里上传文件时还需要使用一个js库;ajaxfileupload.js

在这里插入图片描述

还有,由于要在用户成功登录处访问头像,
这里就在登录时将用户的新头像名称放入session中;

//这里再存入用户的新头像名称;
window.sessionStorage.setItem("userNewFileName",res.data.newFileName);

在这里插入图片描述

在显示用户的头像时,会根据这个session取到的用户新文件的名称是否为空来决定是否显示头像;
newFileName为空,则显示默认路径的图片,否则,就显示用户的头像;

数据库初始化;这边没有新文件名
在这里插入图片描述

启动先看看效果;默认显示的头像出现了;
用户没有头像就显示默认的一个头像;

在这里插入图片描述

点击更新头像;即可弹出模态框;可选择文件;

在这里插入图片描述

mysuccess.html页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模拟登录成功页面</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="js/jquery.1.8.3.min.js"></script>
    <script type="text/javascript" src="js/ajaxfileupload.js"></script>
    <script type="text/javascript">
        //页面加载即触发事件;
        $(function () {
            //获取到session中的信息;
            var peopleN = window.sessionStorage.getItem("people");
            if (peopleN == null) {
                //简易验证,无登录则跳回首页;
                location.replace("loginin.html");
            }

            //取到在登录时放入的用户新文件名
            var newFileName = window.sessionStorage.getItem("userNewFileName");

            //定义的头像位置链接变量 imgLinkSuccess
            var imgLinkSuccess = "";

            if (newFileName != "null") {
                //显示用户的专属文件;
                imgLinkSuccess = "http://localhost:8080/xiaozhire0userimg/" + peopleN + "/" + newFileName;
            } else {
                //若用户没有头像;走默认路径;
                imgLinkSuccess = "http://localhost:8080/xiaozhire0userimg/default/admin.png";
            }
            //将用户的头像存入;
            $("#imgIds").html("<img src='" + imgLinkSuccess + "' width=30  height=30 />");
            //用户姓名放入页面
            $("#spanId").html(peopleN);


        });

        //上传头像时触发;
        function toUpImg() {
            $.ajaxFileUpload({
                    url: 'person/uploadAvatar', //用于文件上传的服务器端请求地址
                    fileElementId: 'fileId', //文件上传域的ID
                    dataType: 'json', //返回值类型 一般设置为json
                    success: function (res) {
                        //测试响应的数据信息;
                        console.log(res)
                        //这里更新后就更改原来位置的头像;
                        var people = window.sessionStorage.getItem("people");
                        //这里取到用户的数据后,将地址拼接放到父窗口; 注意,响应时用了一个类进行封装,所以一这里要取返回结果中的data中的数据;
                        var imgLinkUpdate = "http://localhost:8080/xiaozhire0userimg/"+people+"/"+res.data.newFileName;
                        //测试拼接的链接;
                        console.log(imgLinkUpdate);
                        //将图片链接替换;
                        $("#imgIds").html("<img src='" + imgLinkUpdate + "' width=30  height=30 />");
                    }
                }
            )
        }
    </script>
</head>
<body>
欢迎用户(✪ω✪)<span id="spanId"></span>嘿嘿
您的靓照卡在了奇怪的地方─━ _ ─━✧
<!--放置头像处-->
<span id="imgIds">

</span>
<hr/>
<!--下面的按钮处理更新头像-->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
    更新头像
</button>


<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
                    &times;
                </button>
                <h4 class="modal-title" id="myModalLabel">
                    请选择要上传的头像
                </h4>
            </div>
            <div class="modal-body">
                <form enctype="multipart/form-data">
                    <!--这里限制上传文件的类型-->
                    <input type="file" name="fileName" id="fileId" accept=".png,.gif,.jpg">
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭
                </button>
                <button type="button" class="btn btn-primary" onclick="toUpImg()">
                    点击上传
                </button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal -->
</div>
</body>
</html>

(4)具体的配置和处理

spring-mvc.xml中配置文件解析器

<!--文件解析器,这里配置最大上传大小为10m-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8"></property>
    <property name="maxUploadSize" value="10485760"></property>
</bean>

需要使用的自定义工具类StringUtil;
用来将上传的头像文件名截取更新为新的规则文件名

/**
 *  自定义的String工具类
 */
public class StringUtil {

    /**
     * 截取文件扩展名
     * @param fileName 文件名
     * @return
     */
     public static String subFileType(String fileName){
         if(fileName!=null){
             return fileName.substring(fileName.lastIndexOf(".")+1);
         }
         return null;
     }

    /**
     * 生成新的文件名;
     * @param oldFileName 旧的文件名
     * @return            新的文件名
     */
    public static String getNewFileName(String oldFileName) {
        //利用日期类生成;
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        //拼接进去;
        return sdf.format(date) + "." + subFileType(oldFileName);
    }
}

PersonController;控制层

@RestController
@RequestMapping(path = "/person")
public class PersonController {
    @Autowired
    private PersonService personService;
    //处理用户上传头像;
    @ResponseBody
    @PostMapping("/uploadAvatar")
    public ResultCommon<People> upPeopleImg(@RequestParam("fileName")CommonsMultipartFile file,
                                            HttpSession session){
        ResultCommon<People> resultCommon = null;
        try {
            System.out.println("进入头像上传方法--->");
            //可以取到原始文件名;
            String oldFileName = file.getOriginalFilename();
            System.out.println("获取到上传的文件名称-->"+oldFileName);

            //创建文件夹;(从session中取到登录用户的信息);按照登录者的照片进行创建文件夹;
            People people = (People) session.getAttribute("people");
            File f0 =new File("E:\\xiaozhire0userimg\\"+people.getName());
            //若不存在就为用户创建文件夹;
            if(!f0.exists()){
                f0.mkdir();
            }

            //将旧的文件名转为新的格式文件名;
            String newFileName = StringUtil.getNewFileName(oldFileName);
            System.out.println("可以查看截取的新头像名称"+newFileName);

            //将上传的头像放进创建好的文件夹;
            File f1 = new File(f0,newFileName);
            //文件存入执行;
            file.transferTo(f1);

            //将信息存入数据库;
            //更新信息即可;
            People p = new People();
            p.setId(people.getId());
            p.setOldFileName(oldFileName);
            p.setNewFileName(newFileName);
            //调用方法,按照用户的Id将用户的新旧文件名传入数据表;
            personService.uploadUserImg(p);
            //响应信息;
            resultCommon = new ResultCommon<>(200,"上传成功",p);
        }catch (Exception e){
            e.printStackTrace();
            resultCommon = new ResultCommon<>(500,"服务器异常",null);
        }
        return resultCommon;
    }
}

服务层PersonService

//将服务类注入spring
@Service(value = "personService")
public class PersonService {
    //自动装配数据访问层;
    @Autowired
    PersonMapper personMapper;
    
    @Transactional
    //用户上传头像的方法
    public void uploadUserImg(People p) {
        personMapper.uploadImg(p);
    }
}

数据交互层PersonMapper

//数据访问接口注入spring
@Repository
public interface PersonMapper {
    //用户上传头像的方法;
    void uploadImg(People p);
}

映射的sql文件PersonMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaozhire0.ssm.dao.PersonMapper">
    <!--根据用户ID为用户上传头像-->
    <update id="uploadImg">
        update t_spandmb set `old_file_name`=#{oldFileName},`new_file_name`=#{newFileName}
        where `id`=#{id}
    </update>    
</mapper>

(5)效果展示

图片上传案例的效果图

用户登录进来后;
没有头像时显示默认提供的头像;
在这里插入图片描述

点击更新头像
在这里插入图片描述
比如我选择了这个
在这里插入图片描述
在这里插入图片描述

上传成功
在这里插入图片描述

当然,下次用户登录进来后,还要保证能看到自己的图片

在这里插入图片描述

可以更新头像;
在这里插入图片描述

在这里插入图片描述

我这个图片库在本机;可以看到,已经自动创建了头像库

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小智RE0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值