使用 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>";
    }
}

springmvc前后端整合 springmvc前后端数据交互_springmvc前后端整合

前后端交互过程:

springmvc前后端整合 springmvc前后端数据交互_数据_02

抓包结果:

springmvc前后端整合 springmvc前后端数据交互_数据_03

注意事项

① 作为一个后端程序员,不管前端有没有对参数进行校验工作,我们都应该考虑到异常的情况,所以我们必须在程序开始,进行判空操作。

② 这里使用了 " @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;
    }
}

springmvc前后端整合 springmvc前后端数据交互_mvc_04

抓包结果:

springmvc前后端整合 springmvc前后端数据交互_spring_05

注意事项

① 此次登录我旨在熟悉 ajax 和 Spring MVC 之间的交互,前端传一个 json 格式的数据给后端验证,后端也返回一个 json 数据给前端判断。我之前做过一个由 form 表单实现的登录页面,登录成功后就跳转页面了,可能那个更加科学一些,不过这就看每个人的业务想法是怎么样的了。

② 关于前端的下面代码中的 " data ",表示的后端返回的数据,也即 HTTP 响应中正文的数据。

success:function(data, status) {
    alert(JSON.stringify(data));
}

我经过前端测试,发现 " data " 是一个 Object 类型的对象,这是因为浏览器自动将原本响应正文中的 json 数据转换成了一个对象,所以为了展示给用户看,我们应该再次转换成一个 json 数据,利用 JSON.stringify() 实现。这里再次转换成 json 数据,只是我的个人逻辑,可能在别的场景下,前端应该将数据放在更合适的地方。

但是,最重要的是,我们必须知道,浏览器将后端传来的 json 数据,最终是解析成了一个什么类型的数据。如果不知道它是什么类型的数据,前端就无法真正做到将数据展示出来。

springmvc前后端整合 springmvc前后端数据交互_java_06

③ 在后端,Spring 框架为我们提供了 " StringUtils.hasLength() " 这样的判空方法,这比较方便。此外,我使用了哈希表作为业务逻辑,最终返回的时候,可以很好的与 json 格式的数据相呼应。

三、一个典型的问题

配置过热部署的小伙伴,有时候,我们可能会发现代码没有编写错误,我们检查了前端、后端、交互路径,也没有出错,但是程序就是运行错误。很有可能就是出现了热部署导致文件的丢失情况。

就拿上面的 ajax 的例子来说,刚开始我运行的时候,一切就绪,但访问总是出错,后来才发现是 " jQuery 文件 " 丢失了。因为 ajax 请求需要 " jQuery 文件 " 作为依赖,如果少了此文件,那么就无法正常发送 HTTP 请求。

springmvc前后端整合 springmvc前后端数据交互_spring_07

如上图所示,编译之前的 jQuery 依赖文件还好好地存在 【main】目录中,但是,当 IDEA 生成了 " .class " 文件时,同样的 jQuery 文件却消失了。然而,我们知道,JVM 是只对 " .class " 文件进行运行的,它并不认识 " .java " 文件。

遇到这种情况,我们就应该把整个 【target】目录删除,并重新运行启动类即可。如果不删除此目录重新启动无数次也没用!因为【target】目录依旧有缓存。

所以,后来我就将热部署关掉了,或许它并不适合我,我认为每次重启也挺方便的,热部署每次还要等上几秒,有强迫症的小伙伴,建议关掉。