使用 Spring MVC 来实现简单的前后端交互
- 一、利用 form 表单实现加法计算器
- 注意事项
- 二、利用 ajax 实现登录
- 注意事项
- 三、一个典型的问题
一、利用 form 表单实现加法计算器
前端:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initialscale=
1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>加法计算器</title>
</head>
<body>
<form action="calc" method="POST">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
后端:
@RestController
public class CalcController {
@RequestMapping("/calc")
public String sum(Integer num1, Integer num2) {
if (num1 == null || num2 == null) {
return "<h3>您输入的参数不完整</h3>" + "<a href='javascript:history.go(-1);'>返回</a>";
}
return "<h3>结果:" + (num1 + num2) + "</h3>" + "<a href='javascript:history.go(-1);'>返回</a>";
}
}
前后端交互过程:
抓包结果:
注意事项
① 作为一个后端程序员,不管前端有没有对参数进行校验工作,我们都应该考虑到异常的情况,所以我们必须在程序开始,进行判空操作。
② 这里使用了 " @RestController " 注解。
其代表 " @Controller " + " @ResponseBody ",所以我们应该明白,后端返回的是一个数据,而非一个页面。虽然我们在返回的结果中加上了 " h3 标签、a 标签 " ,但这仅仅是浏览器能够识别的数据,并不足以构成一个真正意义上的 HTML 页面。
二、利用 ajax 实现登录
前端:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initialscale=
1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="js/jquery.min.js"></script>
<title>登录页面</title>
</head>
<body>
<div style="text-align: center;">
<h1>登录</h1>
用户:<input id="username">
<br>
密码:<input id="password" type="password">
<br>
<input type="button" value=" 提交 " onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
</div>
<script>
function mysub() {
// 1. 判空
let username = jQuery("#username");
let password = jQuery("#password");
if( jQuery.trim(username.val()) == "" ) {
alert("请先输入用户名!");
username.focus(); // 光标重置到此元素
return;
}
if( jQuery.trim(password.val()) == "") {
alert("请先输入密码!");
password.focus(); // 光标重置到此元素
return;
}
let body = {
username: username.val(),
password: password.val()
};
jQuery.ajax({
url: "/login2",
type: "POST",
data: JSON.stringify(body),
contentType: "application/json; charset=utf-8",
success:function(data, status) {
alert(data);
}
})
}
</script>
</body>
</html>
后端:
@RestController
public class LoginController {
@RequestMapping("/login2")
public HashMap<String, Object> login2(@RequestBody PersonInfo personInfo) {
HashMap<String, Object> result = new HashMap<>();
int status = 200;
int data = -1; // 约定 data 为 1,表示登录成功,否则登录失败
String message = "";
// 利用 Spring 提供的判空
if (StringUtils.hasLength(personInfo.getUsername()) && StringUtils.hasLength(personInfo.getPassword())) {
if (personInfo.getUsername().equals("Jack") && personInfo.getPassword().equals("123")) {
data = 1;
} else {
message = "您输入的用户名或密码错误!";
}
} else {
message = "非法参数!";
}
// 往哈希表中插入数据,返回的时候,直接放在 HTTP 响应的正文中
result.put("status", status);
result.put("data", data);
result.put("message", message);
return result;
}
}
抓包结果:
注意事项
① 此次登录我旨在熟悉 ajax 和 Spring MVC 之间的交互,前端传一个 json 格式的数据给后端验证,后端也返回一个 json 数据给前端判断。我之前做过一个由 form 表单实现的登录页面,登录成功后就跳转页面了,可能那个更加科学一些,不过这就看每个人的业务想法是怎么样的了。
② 关于前端的下面代码中的 " data ",表示的后端返回的数据,也即 HTTP 响应中正文的数据。
success:function(data, status) {
alert(JSON.stringify(data));
}
我经过前端测试,发现 " data " 是一个 Object 类型的对象,这是因为浏览器自动将原本响应正文中的 json 数据转换成了一个对象,所以为了展示给用户看,我们应该再次转换成一个 json 数据,利用 JSON.stringify() 实现。这里再次转换成 json 数据,只是我的个人逻辑,可能在别的场景下,前端应该将数据放在更合适的地方。
但是,最重要的是,我们必须知道,浏览器将后端传来的 json 数据,最终是解析成了一个什么类型的数据。如果不知道它是什么类型的数据,前端就无法真正做到将数据展示出来。
③ 在后端,Spring 框架为我们提供了 " StringUtils.hasLength() " 这样的判空方法,这比较方便。此外,我使用了哈希表作为业务逻辑,最终返回的时候,可以很好的与 json 格式的数据相呼应。
三、一个典型的问题
配置过热部署的小伙伴,有时候,我们可能会发现代码没有编写错误,我们检查了前端、后端、交互路径,也没有出错,但是程序就是运行错误。很有可能就是出现了热部署导致文件的丢失情况。
就拿上面的 ajax 的例子来说,刚开始我运行的时候,一切就绪,但访问总是出错,后来才发现是 " jQuery 文件 " 丢失了。因为 ajax 请求需要 " jQuery 文件 " 作为依赖,如果少了此文件,那么就无法正常发送 HTTP 请求。
如上图所示,编译之前的 jQuery 依赖文件还好好地存在 【main】目录中,但是,当 IDEA 生成了 " .class " 文件时,同样的 jQuery 文件却消失了。然而,我们知道,JVM 是只对 " .class " 文件进行运行的,它并不认识 " .java " 文件。
遇到这种情况,我们就应该把整个 【target】目录删除,并重新运行启动类即可。如果不删除此目录重新启动无数次也没用!因为【target】目录依旧有缓存。
所以,后来我就将热部署关掉了,或许它并不适合我,我认为每次重启也挺方便的,热部署每次还要等上几秒,有强迫症的小伙伴,建议关掉。