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

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring MVC 学习笔记 --- [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) 
        Spring MVC学习笔记——WebContentGenerator

Spring MVC学习—ViewSolvsolver视图解析器的详细介绍与使用案例

spring mvc 学习笔记---前言

Spring MVC学习笔记——注解式控制器

Spring MVC学习笔记---Spring MVC 的HelloWorld

Spring MVC学习笔记---Spring MVC 的HelloWorld