SpringMVC:Ajax、拦截器、文件上传、文件下载

文章目录

  • SpringMVC - 06
  • 一、Ajax
    • 1. 概述
    • 2. Ajax 异步加载数据
      • 1. 单个数据
      • 2. 对象
    • 3. 实践
    • 4. 总结
  • 二、拦截器
    • 1. 概述
    • 2. 实现
    • 3. 实践
    • 4. 总结
  • 三、文件上传:Upload
    • 1. 准备工作
    • 2. 步骤
    • 3. 效果
  • 四、文件下载:Download
    • 1. 步骤
    • 2. 效果
    • 3. 总结
  • 注意:

SpringMVC - 06

一、Ajax

1. 概述

AjaxAsynchronous Javascript And XML(异步 JavaScript 和 XML)

  1. 使用 Ajax 技术,网页能够快速地将增量更新呈现在用户界面上,而不需要刷新整个页面,这使得程序能够更快地回应用户的操作;

  2. Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术

  3. 使用 Ajax 的最大优点,就是能在不更新整个页面的前提下维护数据,即在不需要刷新页面的情况下,就可以产生局部刷新的效果。

需要用到 jQuery 实现 Ajax,它是一个快速、简洁的 JavaScript 框架,具有 js 的大量函数,引入 jQuery 的方法

  1. 进入 jQuery 官网:点此进入,找到 [Download the uncompressed, development jQuery 3.7.0]
  2. 点击链接,出现 js 代码,通过 Ctrl + S 保存到下载的位置;
  3. 在 web 文件夹新建 static 文件夹,将下载好的 jQuery 框架导入。

2. Ajax 异步加载数据

使用格式

<%-- 引入 jQuery 框架 --%>
<script src="${pageContext.request.contextPath}/static/jquery-3.7.0.js"></script><script>function xxx() {$.post({url:"${pageContext.request.contextPath}/请求地址",data:{"后端参数名":$("#前端参数名").val()},success:function (data) {成功之后执行的回调函数;}, error:function (data) {失败之后执行的回调函数;}})}
</script>

注意

  • script 标签必须成对,并且放在 body 的最后
  • $.post() 相当于 jQuery.post() ,使用时一定要提前引入 jQuery 框架;
  • $.post放在函数内,其中的参数有:
    • url请求地址
    • data :前端要发送给后端的数据,没有数据时可以省略
    • success成功之后执行的回调函数注意这里回调函数中参数 data 与上面的 data 不是同一个,这里是指后端传递给前端的数据;
    • error失败之后执行的回调函数
  • 之前是由后端控制转发或重定向,完成视图的跳转,而现在是由前端 Ajax 来控制,后端只需要提供数据(JSON 字符串)即可,Ajax 把主动权交给前端。

1. 单个数据

举例:当用户输入一个信息后,进行弹窗提示。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>测试</title><script src="${pageContext.request.contextPath}/static/jquery-3.7.0.js"></script><script>function a() {$.post({url:"${pageContext.request.contextPath}/mon/a1",data:{"name":$("#username").val()},success:function (data) {alert(data);}})}</script>
</head>
<body>
<h1><%-- 失去焦点时,发起一个请求(携带信息)到后台 --%>用户名:<input type="text" id="username" οnblur="a()">
</h1>
</body>
</html>

注意

  1. 前端向后端传递单个数据时,data 必须是键值对(JSON 字符串)的形式,这里的 name后端的参数名username前端的参数名
  2. 在 Ajax 中,前端参数的值(例如用户输入的信息)可以通过 $("#前端参数名").val() 的方式取到;
  3. console.log 可以在控制台输出信息
  4. alert 代表弹窗
  5. onblur 代表失去焦点时,执行函数;
  6. 该代码可以执行的操作是:在前端页面中,用户输入用户名信息,失去焦点时,执行函数 a() ,发起 /mon/a1 请求并携带前端数据给后端,后端执行成功(success)后,执行回调函数,此时回调函数的参数 data 为后端返回的数据,进行 alert 弹窗。

后端控制层代码

// 控制层中所有返回的字符串都不会经过视图解析器,而是直接返回字符串
@RestController
@RequestMapping("/mon")
public class AjaxController {@RequestMapping("/a1")public String a1(String name) {System.out.println(name);if ("Sun3285".equals(name)) {return "true";} else {return "false";}}
}

执行

2. 对象

举例:当用户点击【加载数据】按钮时,加载后台中的数据。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>测试</title><script src="${pageContext.request.contextPath}/static/jquery-3.7.0.js"></script><script>$(function () {$("#btn").click(function () {$.post({url:"${pageContext.request.contextPath}/mon/a2",success:function(data) {console.log(data);var obj = JSON.parse(data);console.log(obj);var html = "";for (let i = 0; i < obj.length; i++) {html += "<tr>" +"<td>" + obj[i].id + "</td>" +"<td>" + obj[i].name + "</td>" +"<td>" + obj[i].sex + "</td>" ++ "</tr>";}$("#content").html(html);}})})})</script>
</head>
<body>
<input type="button" value="加载数据" id="btn">
<table><tr><td>编号</td><td>姓名</td><td>性别</td></tr><tbody id="content"><%-- 后台数据 --%></tbody>
</table>
</body>
</html>

注意

  1. 重点看 Ajax 部分,因为前端不给后端传递数据,因此省略了 data;
  2. 后端传递给前端的数据 data 为 JSON 字符串,因此要先通过 JSON.parse(data) 解析为 JavaScript 对象,可以通过 console.log 来看到解析前后的结果;
  3. 该代码可以执行的操作是:在前端页面中,用户点击【加载数据】按钮时,通过 $("#btn").click 可以捕捉到,然后执行函数,发起 /mon/a2 请求给后端,后端执行成功(success)后,执行回调函数,此时回调函数的参数 data 为后端返回的数据,即一个 JSON 字符串,经过前端处理后,在页面中显示信息。

后端控制层代码

@RestController
@RequestMapping("/mon")
public class AjaxController {@RequestMapping("/a2")public String a2() throws JsonProcessingException {ArrayList<Student> studentList = new ArrayList<Student>();Student s1 = new Student(1, "Sun1234", "男");Student s2 = new Student(2, "Sun3285", "男");Student s3 = new Student(3, "Sun4399", "女");Collections.addAll(studentList, s1, s2, s3);// 后端传递给前端的是一个 JSON 字符串return new ObjectMapper().writeValueAsString(studentList);}
}

执行

3. 实践

需求:输入用户名和密码时,动态显示输入信息是否正确。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title><script src="${pageContext.request.contextPath}/static/jquery-3.7.0.js"></script><script>function login1() {$.post({url:"${pageContext.request.contextPath}/mon/login1",data:{"username":$("#username").val()},success:function (data) {console.log(data);if (data === "OK") {$("#usernameInfo").css("color", "green");} else {$("#usernameInfo").css("color", "red");}$("#usernameInfo").html(data);}})}function login2() {$.post({url:"${pageContext.request.contextPath}/mon/login2",data:{"username":$("#username").val(), "password":$("#password").val()},success:function (data) {console.log(data);if (data === "OK") {$("#passwordInfo").css("color", "green");} else {$("#passwordInfo").css("color", "red");}$("#passwordInfo").html(data);}})}</script>
</head>
<body>
<p>用户名:<input type="text" id="username" οnblur="login1()"><span id="usernameInfo"></span><br>密  码:<input type="text" id="password" οnblur="login2()"><span id="passwordInfo"></span>
</p>
</body>
</html>

后端控制层代码

@RestController
@RequestMapping("/mon")
public class AjaxController {@RequestMapping("/login1")public String login1(String username) {if ("Sun3285".equals(username)) {return "OK";} else {return "用户名输入有误";}}@RequestMapping("/login2")public String login2(String username, String password) {String result = login1(username);if ("OK".equals(result)) {if ("123456".equals(password)) {return "OK";} else {return "密码输入有误";}} else {return result;}}
}

注意:判断密码是否正确的前提是:先要判断用户名是否正确。

执行

4. 总结

  1. js 中三个等号为严格等于,指数据类型都要相等;
  2. 之前是由后端控制转发或重定向,完成视图的跳转,而现在是由前端 Ajax 来控制,后端只需要提供数据(JSON 字符串)即可,Ajax 把主动权交给前端;
  3. 前后端之间交互数据是以 JSON 字符串的形式;
  4. 标签中 id 和 name 的区别
    • id 一般用于 css 和 js 中引用,name 用于表单提交只有加了 name 属性的标签元素才会提交到服务器;
    • id 是唯一的标识符,不允许有重复值,可以通过它的值来获得对应的 html 标签对象,相当于人的身份证具有唯一性;
    • name 是控件的名字,当需要把控件所关联的数据传递到数据库时,就必须要设置 name 属性,相当于人的姓名,可以重名,用 value 可以设置控件的默认值。

二、拦截器

1. 概述

拦截器AOP 思想的具体应用,拦截器拦截的是请求,不拦截静态资源。

功能:用于对 SpringMVC 处理器进行预处理和后处理,可以自己定义一些拦截器来实现特定的功能。

过滤器和拦截器的区别

  • 过滤器

    1. 是 servlet 规范中的一部分,任何 JavaWeb 工程中都可以使用;
    2. 在 url-pattern 中配置了 /* 之后,可以对所有要访问的资源进行过滤;
    3. web.xml 中进行配置。
  • 拦截器

    1. 拦截器是 SpringMVC 框架的,只有使用了 SpringMVC 框架的工程才能使用;
    2. 拦截器只会拦截访问的控制器方法(控制类中的方法),如果访问的是 jsp/html/css/image/js 是不会进行拦截的;
    3. 在 Spring 配置文件中进行配置(因为拦截器是 SpringMVC 框架独有的)。

2. 实现

实现拦截器的步骤

  1. 自定义一个拦截器,实现 HandlerInterceptor 接口,重写方法;
  2. 在 Spring 配置文件中,配置拦截器,包括使用的拦截器以及要拦截的请求。
// 第一步:自定义一个拦截器 MyInterceptor,实现 HandlerInterceptor 接口,重写方法
public class MyInterceptor implements HandlerInterceptor {// 处理前public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return false;}// 处理后public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}// 清理public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

注意:preHandle 方法中,返回值为 true,表示执行下一个拦截器(放行),返回值为 false,表示不执行下一个拦截器(拦截)。

<!-- 第二步:在 Spring 配置文件中,对拦截器进行配置 -->
<mvc:interceptors><mvc:interceptor><!-- /** 表示所有请求都会经过拦截器 --><mvc:mapping path="/**"/><!-- 指定使用的拦截器 --><bean class="com.Sun3285.config.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>

3. 实践

需求:登录判断验证,如果进行了登录操作,并且用户名和密码正确,才可以进入首页,否则不能直接进入首页。

拦截前:可以进入登录界面进行登录操作,输入正确的用户名和密码,进入主界面,也可以在首页上直接点击超链接,进入主界面。

点击【主页面】时使用拦截器拦截,拦截的依据是:是否在 Session 中存放了指定的信息,因为只有登录成功,才会在 Session 中存放指定信息 usernameID。

第一步:自定义拦截器,如果 Session 中存放了指定的信息(进行了登录操作),就放行,否则,跳转到登录页面。

public class LoginInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session = request.getSession();if (session.getAttribute("usernameID") != null) {return true;}request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);return false;}
}

第二步:在 Spring 配置文件中,配置拦截器,在首页点击【主页面】超链接时,进行拦截。

<!-- 拦截器配置 -->
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/toMain"/><bean class="com.Sun3285.config.LoginInterceptor"/></mvc:interceptor>
</mvc:interceptors>

运行结果

  • 没有进行登录操作,直接在首页点击【主页面】时,拦截器拦截,并跳转到登录页面。

  • 进行了登录,再在首页点击【主页面】时,可以直接跳转到主页面,因为此时 Session 中存放了指定的信息,拦截器放行

  • 此时关闭浏览器,重新打开,再在首页点击【主页面】时,拦截器拦截,并跳转到登录页面,因为此时拦截器得到的 session 为新的 session,其中没有存放指定的信息 usernameID。

4. 总结

  1. 在 WEB-INF 下的所有页面或者资源,只能通过 controller 或 servlet 进行访问;
  2. 请求转发可以访问 WEB-INF 下的所有页面或者资源,重定向不可以
  3. 可以在控制类的方法参数中直接拿到一些对象,如:HttpSession session、HttpServletRequest request、HttpServletResponse response 等,然后在方法内进行进一步操作。

三、文件上传:Upload

1. 准备工作

如果想使用 Spring 的文件上传功能,需要在上下文中配置 MultipartResolver。

为了能够上传文件,前端表单要求

  1. 必须将表单的 method 设置为 POST;
  2. 将 enctype 设置为 multipart/form-data,这样,浏览器才会把用户选择的文件以二进制数据发送给服务器。

后端要求

  1. 导入依赖:commons-fileupload
<!-- 文件上传 -->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>

2. 步骤

文件上传的步骤

  1. 导入依赖;
  2. 编写前端页面:建立表单;
  3. 编写控制类,实现文件上传;
  4. 在 Spring 配置文件中配置文件上传。
  • 前端页面

  • 控制类

@Controller
public class FileController {// @RequestParam("file") 将 name="file" 控件得到的文件封装为 CommonsMultipartFile 对象@RequestMapping("/upload")public String uplode(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request) throws IOException {// 获取文件名String uploadFilename = file.getOriginalFilename();// 上传路径保存设置String path = request.getServletContext().getRealPath("/upload");File realPath = new File(path);if (!realPath.exists()) {realPath.mkdir();// realPath.mkdirs();}// 输出上传文件地址System.out.println("上传文件保存地址:" + realPath);// 通过 CommonsMultipartFile 的方法直接写文件file.transferTo(new File(realPath + "/" + uploadFilename));return "redirect:/index.jsp";}
}

注意:这部分代码可以直接使用只需要按需求改一下上传路径 path 即可,其中 upload 为新创建的文件夹,存放上传的文件。这里也可以把上传路径 path 直接用一个字符串表示。

  • 配置文件上传
<!-- 在 Spring 配置文件中配置文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 请求的编码格式 --><property name="defaultEncoding" value="utf-8"/><!-- 上传文件大小上限,可以省略,单位为字节(1MB=1048576字节) --><property name="maxUploadSize" value="10485760"/>
</bean>

3. 效果

文件上传后,控制台输出上传文件的地址,并且可以找到已上传的文件


四、文件下载:Download

1. 步骤

固定代码

@Controller
public class FileController {@RequestMapping("/download")public String download(HttpServletRequest request,HttpServletResponse response) throws IOException {// 要下载的文件地址和文件名String path = request.getServletContext().getRealPath("/files");String fileName = "导入的依赖总结.txt";File file = new File(path, fileName);// 设置 response 响应头response.reset();   // 设置页面不缓存,清空 bufferresponse.setCharacterEncoding("utf-8");  // 字符编码response.setContentType("multipart/form-data");  // 二进制传输数据// 设置下载文件response.setHeader("Content-Disposition","attachment;fileName=" + URLEncoder.encode(fileName, "utf-8"));// 读取文件:输入流InputStream is = new FileInputStream(file);InputStream bis = new BufferedInputStream(is);// 写出文件:输出流OutputStream os = response.getOutputStream();OutputStream bos = new BufferedOutputStream(os);// 下载操作(读取、写出)byte[] buffer = new byte[1024];int len = 0;while ((len = bis.read(buffer)) != 0) {bos.write(buffer, 0, len);bos.flush();}// 关闭资源bos.close();bis.close();return null;}
}

注意

  1. 这部分代码可以直接使用只需要按需求改一下要下载的文件地址和文件名,其中
    • 被下载文件的地址:这里是放在了 web 文件夹下的 files 文件夹中,最后会在生成的 out 文件夹下的子项目中;
    • 文件名:被下载的文件名。
  2. 记得最后要关闭资源,后开先关

2. 效果

无法下载文件,后端代码执行成功

判断应该是浏览器阻止了下载,更换浏览器再次尝试,可以下载成功

3. 总结

  • 上传路径 path 和被下载的文件地址 path 也都可以直接用一个字符串表示:
    • 上传路径 path 一般通过 request.getServletContext().getRealPath("/upload") 来将文件上传到服务器生成的 out 目录下的子项目中的 upload 包(如果没有 upload 包,会自动新建)中;
    • 下载时,要提前在服务器中准备好被下载的文件,可以在 web 包下建立 files 包,用来存放被下载的文件,此时,被下载的文件地址 path 可以由 request.getServletContext().getRealPath("/files") 得到。
  • 上传是用户通过前端表单操作将文件上传到服务器;
  • 下载是用户点击前端超链接将服务器中的文件下载到浏览器(客户端本地文件)。

注意:

  1. jQuery 官网:https://jquery.com/download/
  2. 需要将 JavaScript 的版本变为 6,方法如下:

  1. 拦截器和文件上传的配置都是在 Spring 的配置文件中,因为都是基于 SpringMVC 框架的。
  2. 搭建完环境,要先测试一下能不能运行,环境是否有问题。
  3. 删除项目中的子模块方法:选中子模块,右键选择 Remove Module 移除模块,然后再右键删除文件夹,注意:要在父模块的 pom.xml 中删除对应的子模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/295672.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI 绘画StableDiffusionWebui图生图

介绍 stable-diffusion-webui AI绘画工具&#xff0c;本文介绍图生图&#xff0c;以一张图片做底图优化生成。 例如&#xff1a;上传一张真人照片&#xff0c;让AI把他改绘成动漫人物&#xff1b;上传画作线稿&#xff0c;让AI自动上色&#xff1b;上传一张黑白照&#xff0c…

第11章 GUI Page417~418 步骤五 支持方框 使用宏定义

运行效果&#xff1a; 原来的创建item的方式&#xff1a; 使用宏定义的方式&#xff1a;

Vue3+SpringBoot实现文件上传详细教程

文件上传的功能实现是我们做Web应用时候最为常见的应用场景&#xff0c;比如&#xff1a;实现头像的上传&#xff0c;Excel文件数据的导入等功能&#xff0c;都需要我们先实现文件的上传&#xff0c;然后再做图片的裁剪&#xff0c;excel数据的解析入库等后续操作。 今天通过这…

Linux数据库主从复制(单主单从)

MySQL主从复制的优点包括&#xff1a; 1、横向扩展解决方案 - 在多个从站之间分配负载以提高性能。在此环境中&#xff0c;所有写入和更新都必须在主服务器上进行。但是&#xff0c;读取可以在一个或多个从设备上进行。该模型可以提高写入性能&#xff08;因为主设备专用于更新…

【Linux驱动】字符设备驱动程序框架 | LED驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;Hello驱动程序⚽驱动程序框架⚽编程 &#x1f3c0;LED驱动⚽配置GPIO⚽编程驱动…

机器学习---比较单个学习器与Bagging集成的偏差-方差分解、在Iris数据集的不同特征子集上使用不同的分类器进行训练和可视化

1. Bagging 说明并比较了预期均方误差的偏差方差分解&#xff0c;单个学习器与bagging集成的比较。 在回归中&#xff0c;估计器的预期均方误差可以根据偏差、方差和噪声进行分解。 在回归问题的数据集上的平均值上&#xff0c;偏差项测量估计器的预测与问题的最佳可能估计器…

大语言模型的三种主要架构 Decoder-Only、Encoder-Only、Encoder-Decoder

现代大型语言模型&#xff08;LLM&#xff09;的演变进化树&#xff0c;如下图&#xff1a; https://arxiv.org/pdf/2304.13712.pdf 基于 Transformer 模型以非灰色显示&#xff1a; decoder-only 模型在蓝色分支&#xff0c; encoder-only 模型在粉色分支&#xff0c; encod…

在Linux下探索MinIO存储服务如何远程上传文件

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 创建Buckets和Access Keys二. Linux 安装Cpolar三. 创建连接MinIO服务公网地…

JavaWeb—html, css, javascript, dom,xml, tomcatservlet

文章目录 快捷键HTML**常用特殊字符替代:****标题****超链接标签****无序列表、有序列表****无序列表**:ul/li 基本语法**有序列表ol/li:****图像标签(img)**** 表格(table)标签****表格标签-跨行跨列表格****form(表单)标签介绍****表单form提交注意事项**div 标签p 标签sp…

el-select如何去掉placeholder属性

功能要求是&#xff1a;当el-select的disabled属性为true的时候不展示“请选择”字样 1、要去掉 el-select 元素的 placeholder 属性&#xff0c;可以在代码中将其设置为空字符串。 <el-select placeholder"" ...></el-select> 注意&#xff1a;这种方…

HBase基础知识(三):HBase架构进阶、读写流程、MemStoreFlush、StoreFile Compaction、Region Split

1. 架构原理 1&#xff09;StoreFile 保存实际数据的物理文件&#xff0c;StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile&#xff08;HFile&#xff09;&#xff0c;数据在每个StoreFile中都是有序的。 2&#xff09;MemStore 写缓存&#xff0c;由于…

LED灯驱动模块加载与卸载代码框架

一. 简介 本文来编写 LED灯驱动模块加载与卸载的代码。 二. LED灯驱动模块加载与卸载代码框架 1. 创建工程 我的驱动代码存放目录&#xff1a; ubuntu系统 /home/wangtian/zhengdian_Linux/Linux_Drivers 目录下。 进入 /home/wangtian/zhengdian_Linux/Linux_Drivers 目…