- SpringMVC 基础 查看链接
一、AJAX
1.1 简介
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML);
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术;
AJAX 不是一种新的编程语言,而是一种用于创建更好更快,以及交互性更强的 Web 应用程序的技术;
在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来,Google Suggest 能够自动完成搜索单词;
-
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当我们在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表,如百度的搜索框:
传统的网页(即不用 AJAX 技术的网页)想要更新内容或者提交一个表单,都需要重新加载整个网页;
使用 AJAX 技术的网页,通过在后台服务器,进行少量的数据交换,就可以实现异步、局部更新;
使用 AJAX,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的 Web 用户界面;
1.2 伪造 AJAX
-
可以使用前端的一个标签,来伪造一个 ajax 的样子:
iframe 标签
- 新建模块,并导入 web 支持;
- 配置
web.xml
及 springMVC 配置文件,运行 Tomcat 测试环境; - 编写 html 页面,使用 iframe 测试,感受下效果:
iframe伪造ajax 请输入要加载的地址:
加载页面位置:
- 使用 IDEA 打开浏览器进行测试;
小结:
- 利用 AJAX 可以实现:
- 注册时,输入用户名,自动检测用户是否已经存在;
- 登陆时,提示用户名,密码错误;
- 删除数据行时,将行 ID 发送到后台,后台在数据库中删除,数据库删除成功后,在页面 DOM 中,将数据行也删除;
- ...等等;
1.3 jQuery.ajax
- jQuery 3.6.0 开发版 下载链接
- Ajax 的核心是 XMLHttpRequest 对象(XHR):
- XHR 为向服务器发送请求和解析服务器响应,提供了接口,能够以异步方式,从服务器获取新数据;
- jQuery 提供多个与 AJAX 有关的方法;
- 通过 jQuery AJAX 方法,能够使用 HTTP Get 和 HTTP Post,从远程服务器上请求文本、HTML、XML 或 JSON,同时能够把这些外部数据,直接载入网页的被选元素中;
- jQuery(是一个库) 不是生产者,而是大自然搬运工;
- jQuery Ajax 本质就是 XMLHttpRequest,对它进行了封装,方便调用:
jQuery.ajax(...)
/*
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
*/
测试一:HttpServletResponse 实现
- 使用最原始的 HttpServletResponse 处理,最简单,最通用:
- 配置
web.xml
和 springmvc 的配置文件:- 注意:静态资源过滤和注解驱动配置;
- 创建 Controll:AjaxController
// 不走视图页面,直接返回字符串
@RestController
public class AjaxController {
@RequestMapping("/a1")
public void ajax1(String name, HttpServletResponse response) throws IOException {
System.out.println("前端传递参数:" + name);
if ("admin".equals(name)) {
response.getWriter().println("true");
} else {
response.getWriter().println("false");
}
}
}
- 导入 jQuery,可以使用在线的 CDN,也可以下载导入:
<%----%>
- 编写 index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
<%----%>
<%--onblur:失去焦点触发事件--%>
用户名:
-
启动 Tomcat 测试:
- 打开浏览器的控制台,当鼠标离开输入框时,可以看到发出了一个 ajax 的请求;
-
流程分析:
测试二:SpringMVC、JSON 方式实现
- 需要导入 Jackson 依赖:否则请求路径时,报错 406
com.fasterxml.jackson.core
jackson-databind
2.13.2.2
- 创建实体类:user
- 使用 lombok,需要事先导入依赖;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
- 在 Controller 类中添加方法:
- 获取一个集合对象,展示到前端页面;
@RequestMapping("/a2")
public List ajax2() {
List list = new ArrayList<>();
list.add(new User("test01", 20, "男"));
list.add(new User("test02", 21, "女"));
list.add(new User("test03", 20, "男"));
// 类中使用@RestController注解,将list转成json格式返回
return list;
}
- 前端页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--jQuery--%>
姓名
年龄
性别
-
运行测试:
1.4 AJAX 注册提示
- 在 Controller 类中,添加方法:
@RequestMapping("/a3")
public String ajax3(String name, String pwd) {
String msg = "";
if (name != null) {
// admin:模拟数据库查询的数据
if ("admin".equals(name)) {
msg = "OK";
} else {
msg = "用户名有误";
}
}
if (pwd != null) {
// 123456:模拟数据库查询的数据
if ("123456".equals(pwd)) {
msg = "OK";
} else {
msg = "密码有误";
}
}
// 类中使用@RestController注解,将msg转成json格式返回
return msg;
}
- 创建前端页面:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
login
<%--onblur:失去焦点触发事件--%>
用户名:
密码:
- 处理 JSON 乱码:SpringMVC 配置文件中进行配置
-
运行测试:
1.5 获取 baidu 接口 Demo
JSONP百度搜索
二、拦截器
2.1 概述
- SpringMVC 的处理器,拦截器,类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理,可以自定义拦截器,实现特定的功能;
- 过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用;
- 过滤器:
- servlet 规范中的一部分,任何 Java web 工程都可以使用;
- 在
url-pattern
中配置了/*
之后,可以对所有要访问的资源,进行拦截;
- 拦截器:
- 拦截器是 SpringMVC 框架自有的,只有使用了 SpringMVC 框架的工程才能使用;
- 拦截器只会拦截访问控制器方法,如果访问的是 jsp、html、css、image、js,是不会进行拦截的;
2.2 自定义拦截器
- 要自定义拦截器,必须实现 HandlerInterceptor 接口;
- 创建新模块,并添加 web 支持;
- 配置
web.xml
和 springmvc 配置文件; - 创建拦截器:config 目录下,创建 MyInterceptor
public class MyInterceptor implements HandlerInterceptor {
/*
如果返回true执行下一个拦截器
如果返回false就不执行下一个拦截器
*/
// 在请求处理的方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("------------处理前------------");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
// 在请求处理方法执行之后执行(一般用于处理日志)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
// 在dispatcherServlet处理后执行,做清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("------------清理------------");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
- 在 SpringMVC 的配置文件中,配置拦截器:
- 创建 Controller,接收请求:
@RestController
public class TestController {
@RequestMapping("/interceptor")
public String test2() {
System.out.println("控制器中的方法执行了");
return "hello";
}
- 编写前端:index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
拦截器测试
-
配置 Tomcat,启动测试:
2.3 验证用户是否登录 (认证用户)
实现思路:
- 有一个登陆页面,需要写一个 controller 访问页面;
- 登陆页面有一个提交表单的动作,需要在 controller 中处理,判断用户名、密码是否正确,如果正确,向 session 中写入用户信息,返回登陆成功信息;
- 拦截用户请求,判断用户是否登陆,如果用户已经登陆,放行,如果用户未登陆,跳转到登陆页面;
测试:
- 创建登陆页面:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
首页
登录
成功页面
- 创建 Controller 类,处理请求:
@Controller
@RequestMapping("/user")
public class LoginController {
// 跳转到登录页面
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
// 跳转到成功页面
@RequestMapping("/toSuccess")
public String toSuccess() {
return "success";
}
// 登陆提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) {
// 把用户的信息存在Session中
session.setAttribute("user", username);
return "success";
}
// 退出登陆
@RequestMapping("/logout")
public String logout(HttpSession session) {
// 移除Session
session.removeAttribute("user");
// 手动注销Session
// session.invalidate();
return "login";
}
}
- 创建登陆成功的页面:
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录成功
登录成功页面
${user}
注销
- 在 index 页面上测试跳转,启动 Tomcat 测试,未登录也可以进入主页:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
首页
登录
成功页面
- 创建登录拦截器:
public class LoginInterceptor implements HandlerInterceptor {
// 在请求处理的方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是登陆页面则放行
if (request.getRequestURI().contains("toLogin")) {
return true;
}
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已登陆也放行
if (session.getAttribute("user") != null) {
return true;
}
// 用户没有登陆跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
- 在 SpringMVC 的配置文件中,注册拦截器:
- 再次重启 Tomcat 测试,可以实现登录拦截功能;
三、文件上传和下载
3.1 概述
- 文件上传是项目开发中最常见的功能之一,springMVC 可以很好的支持文件上传,但是 SpringMVC 上下文中,默认没有装配 MultipartResolver,因此,默认情况下,不能处理文件上传工作;
- 如果想使用 Spring 的文件上传功能,则需要在上下文中配置MultipartResolver;
- 前端表单要求:为了能上传文件,必须将表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data,只有在这样的情况下,浏览器才会把用户选择的文件,以二进制数据发送给服务器;
- 表单中的 enctype 属性说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单,会将表单域中的值处理成 URL 编码方式;
- multipart/form-data:以二进制流的方式,来处理表单数据,这种编码方式,会把文件域指定文件的内容,也封装到请求参数中,不会对字符编码;
- text/plain:除了把空格转换为
+
号外,其他字符都不做编码处理,这种方式适用 直接通过表单发送邮件;
- 一旦设置了enctype 为 multipart/form-data,浏览器即会采用二进制流的方式,来处理表单数据,而对于文件上传的处理,则涉及在服务器端解析原始的 HTTP 响应;
- 在 2003 年,Apache Software Foundation 发布了开源的 Commons FileUpload 组件,很快成为 Servlet/JSP 程序员上传文件的最佳选择;
- Servlet3.0 规范已经提供方法来处理文件上传,但这种上传需要在 Servlet 中完成;
- Spring MVC 提供了更简单的封装;
- Spring MVC 为文件上传,提供了直接的支持,这种支持是用 即插即用 的 MultipartResolver 实现的;
- Spring MVC 使用 Apache Commons FileUpload 技术实现了一个 MultipartResolver 实现类
CommonsMultipartResolver
因此,SpringMVC 的文件上传,还需要依赖 Apache Commons FileUpload 的组件;
3.2 文件上传
- 创建新模块,并添加 web 框架支持;
- 配置
web.xml
及 SpringMVC 配置文件; - 配置 Tomcat,启动测试环境;
- 导入文件上传的 jar 包,commons-fileupload 或 Maven 依赖:
commons-fileupload
commons-fileupload
1.4
javax.servlet
javax.servlet-api
4.0.1
- 在 SpringMVC 配置文件中配置 bean:
multipartResolver
- id 必须为:multipartResolver,否则报400错误;
- CommonsMultipartFile 的常用方法:
- String getOriginalFilename():获取上传文件的原名;
- InputStream getInputStream():获取文件流;
- void transferTo(File dest):将上传文件,保存到一个目录文件中;
- 编写前端页面:
index.jsp
- 创建 Controller 类:FileController
上传方式一:
@Controller
public class FileController {
// 上传方式 1:
// @RequestParam("file"):将name=file控件得到的文件封装成CommonsMultipartFile对象
// 批量上传,CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// 获取文件名:file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
// 如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)) {
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : " + uploadFileName);
// 上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
// 如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件保存地址:" + realPath);
// 文件输入流
InputStream is = file.getInputStream();
// 文件输出流
OutputStream os = new FileOutputStream(new File(realPath, uploadFileName));
// 读取写出
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}
- 测试上传文件;
上传方式二:
- 采用
file.transferTo
来保存上传的文件; - 在 FileController 类中添加方法:
/*
上传方式 2:
采用file.transferTo来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file,
HttpServletRequest request) throws IOException {
// 上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
// 上传文件地址
System.out.println("上传文件保存地址:" + realPath);
// 通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath + "/" +
file.getOriginalFilename()));
return "redirect:/index.jsp";
}
- 修改前端表单提交地址;
- 运行测试;
3.3 文件下载
-
文件下载步骤:
- 设置 response 响应头;
- 读取文件:InputStream;
- 写出文件:OutputStream;
- 执行操作;
- 关闭流(先开后关);
代码实现:
// 文件下载
@RequestMapping("/download")
public String downloads(HttpServletResponse response, HttpServletRequest request) throws Exception {
// 要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.png";
// 1. 设置response 响应头
// 设置页面不缓存,清空buffer
response.reset();
// 字符编码
response.setCharacterEncoding("UTF-8");
// 二进制传输数据
response.setContentType("multipart/form-data");
// 设置响应头
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path, fileName);
// 2. 读取文件:输入流
InputStream input = new FileInputStream(file);
// 3. 写出文件:输出流
OutputStream out = response.getOutputStream();
byte[] buff = new byte[1024];
int index = 0;
// 4. 执行写出操作
while ((index = input.read(buff)) != -1) {
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
-
创建对应目录及需要下载的文件:
对应前端页面:
点击下载
- 运行测试;