我们在四个小案例中,能学到以下知识:

1. 理解前后端交互过程

2. 接⼝传参,数据返回,以及⻚⾯展⽰

目录

一、计算器(前后端交互)

 需求分析

接口定义

请求参数

 响应数据

 代码实现

二、用户登录(Session用法)

需求分析

接口定义

 1.校验接口

请求参数

 响应数据

 2.查询登录用户接口

【请求参数】

【响应数据】

代码实现 

三、留言板(前后端JSON相关操作)

 需求分析:

 接口定义

1.获取全部留言

请求

响应数据

 2.发表留言

请求

响应

代码实现 

四、图书管理(综合性案例) 

需求分析

1.用户登录

2.图书列表


我们这篇博客将会完成前3个期,也就是立项期、设计期、生产期。

我们将会用 需求分析接口定义代码实现 来简单带过这三个期,最主要是为了让大家明白前后端的交互。

啥是需求分析?

答:开发团队需要跟客户沟通,根据需要来开发,需要也就是需求分析,这个东西是用来做什么的,简单的流程是怎么样的,也就是对软件的期望。

啥是接口定义?

这个接口并不是我们学面向对象的那个接口,我们管接口又叫API,简单来说就是我们写代码的时候,需要明白的一些东西,比如传参的变量名,url,要请求什么样的http请求,需要接受什么http请求。

为什么要有接口文档?

因为前后端是分离的,所以我们需要提前约定好,那就可以单独开发,双方都做好之后就一起整合到一起,方便又快。

接口的组成一般有如下几点:

  1. 接口名称:即接口的名称或标识符,用于区分不同的接口。
  2. 接口方法:即接口所提供的方法,包括 GET、POST、PUT、DELETE 等。
  3. 接口地址:即接口的访问地址。
  4. 请求参数:即接口所需要的输入参数,包括参数名称、参数类型、参数说明等。
  5. 响应参数:即接口所返回的输出结果,包括返回值的类型、名称、说明等。

一、计算器(前后端交互)

需求:输⼊两个整数,点击"点击相加"按钮,显⽰计算结果 

 需求分析

加法计算器功能,对两个整数进⾏相加,需要客⼾端提供参与计算的两个数,服务端返回这两个整数计算的结果

接口定义

接口名称、方法

【请求路径】

calc/sum

【请求⽅式】

GET/POST

【接⼝描述】

计算两个整数相加

请求参数
参数名 类型 是否必须 备注
num1 Integer 两个数相加的第一个数
num1 Integer 两个数相加的第二个数

比如:num1=5&num2=8 

 响应数据

【Content-Type】

text/html

【响应内容】

计算机计算结果 : 8

 代码实现

后端,我们通过前端传值num1和num2,然后直接计算,前端访问的路径就是[请求路径]calc/sum,[请求⽅式]GET/POST是都可以传,[Content-Type]text/html就是普通的字符串,[响应内容]就是咱们return的值。

@RequestMapping("calc")
@RestController
public class CalcController {
    @RequestMapping("sum")
    public String sum(@RequestParam Integer num1,@RequestParam Integer num2){
        int sum=num1+num2;
        return "计算机计算结果:"+sum;
    }
}

前端,我们放在static中,通过form表单发送数据给后端,input输入num1和num2,这样点击submit就会传到action的[请求路径]calc/sum上

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
     <form action="calc/sum" 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>

我们运行后端之后,通过浏览器访问:http://127.0.0.1:8080/login.html 

127.0.0.1是我们的本机

8080是我们idea的端口号

login.html是前端的名字

为什么访问的是login.html而不是calc/login?

答:因为我们得有人赋值给num1和num2,才能进行计算。login.html有form表单给我们赋值 

二、用户登录(Session用法)

这里有两个接口,一个是检验用户登录是否正确的接口,一个是查询登录用户的接口

需求分析

后端开发⼈员⽽⾔, 不涉及前端⻚⾯的展⽰, 只需要提供两个功能:

1. 登录⻚⾯: 通过账号和密码, 校验输⼊的账号密码是否正确, 并告知前端

2. ⾸⻚: 告知前端当前登录⽤⼾. 如果当前已有⽤⼾登录, 返回登录的账号, 如果没有, 返回空

接口定义

 1.校验接口

【请求路径】

/user/login

【请求⽅式】

POST

【接⼝描述】

校验账号密码是否正确

请求参数
参数名 参数类型 是否必传 备注

userName

String 校验的账号
password String 校验的密码
 响应数据

【Content-Type】

text/html

【响应内容】

true //账号密码验证成功

false//账号密码验证失败

 2.查询登录用户接口

【请求路径】

/user/getLoginUser

【请求⽅式】

GET

【接⼝描述】

查询当前登录的⽤⼾

【请求参数】

【响应数据】

【Content-Type】

text/html

【响应内容】

zhangsan 

代码实现 

【后端】

1.我们通过前端传值userName和password,

然后直接计算,前端访问的路径就是[请求路径]/user/login,

[请求⽅式]POST所以我们需要在RequestMapping定义method为RequestMethod.POST,[Content-Type]为true或者false所以返回值为boolean,

[响应内容]就是咱们return的值。

getUser这个方法也是同理。只要根据接口定义就可以写出来了。

2.HttpSession是Session接口,如果没有赋值,则会自动创建一个空的session,来存储咱们的用户信息。如果重启服务器,session会丢失。

为什么需要Session?

答:因为http是无状态的,你换到别的网址,你的信息就没有保存了,所以我们需要手动设置session来存储,不然就获取不到了。

@RequestMapping("/user")
@RestController
public class LoginController {
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public boolean login(@RequestParam String userName,
                         @RequestParam String password,
                         HttpSession session){
        if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){
            return false;
        }if("admin".equals(userName)&&"admin".equals(password)){
            session.setAttribute("userName",userName);
            return true;
        }
        return false;
    }
    @RequestMapping(value = "/getLoginUser",method =RequestMethod.GET)
    public String getUser(HttpSession session){
        String userName= (String) session.getAttribute("userName");
        return userName;
    }
}

【前端】

 1.这里的jQuery文件直接可以上百度搜索,然后另存为,复制到static文件夹里面就好了。

2.重要的是有个Ajax,前端传值并非只能靠form表单,ajax它是前端的一个传值给后端的,它是异步的。

啥是异步?

答:就是可以和后端一起执行,比如邮箱的登录页面,我们输入一个邮箱名,它会给我们显示,这个邮箱名有人注册了,请换一个,这个就是异步,

它会把这个名字发送给后端,然后后端调用数据库,数据库发现有人了,就返回给前端说有人了,让你换一下,这个是可以一起进行的。

ajax语法:

$.ajax({

        type:"http[请求⽅式]",

        url:"后端的[请求路径]",

        data:{

                后端数据:$("#前端id名").val(),

                .....

        },

        success:function(后端返回来的结果){

                ... //(如果成功的业务)

        }

});

这里的data里面的后端数据,也就是传值给后端的请求参数,

通过type[请求⽅式] 和对应后端的url[请求路径],就可以传给后端了,如果要传的值是class,就是 .  如果的id就是#。

注意修改了前端之后,一定要按ctrl+f5强刷,然后看看f12有没有修改的代码有没有同步上来。并且Jquery的文件,有些是起不来作用的,不行就再换一个Jquery文件,网上大把。

login.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>登录页面</title>
</head>

<body>
  <h1>用户登录</h1>
  用户名:<input name="userName" type="text" id="userName"><br>
  密码:<input name="password" type="password" id="password"><br>
  <input type="button" value="登录" onclick="login()">

  <script src="./js/jquery.min.js"></script>
  <script>
    function login() {
      $.ajax({
        type: "post",
        url: "user/login",
        data: {
          userName: $("#userName").val(),
          password: $("#password").val()
        },
        success: function (ret) {
          if (ret) {
            location.href = "index.html";
          } else {
            alert("账号或密码错误");
          }
        }
      });
    }

  </script>
</body>
</html>


index.html
<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>用户登录首页</title>
</head>

<body>
    登录人: <span id="loginUser"></span>

    <script src="./js/jquery.min.js"></script>
    <script>
        $.ajax({
            type: "get",
            url: "user/getLoginUser",
            success: function (ret) {
                $("#loginUser").text(ret);
            }
        });
    </script>
</body>

</html>

 我们运行后端之后,通过浏览器访问:http://127.0.0.1:8080/login.html ,点击登录,就会跳转到index.html了

三、留言板(前后端JSON相关操作)

需求:1. 输⼊留⾔信息, 点击提交,后端把数据存储起来. 2. ⻚⾯展⽰输⼊的表⽩墙的信息 

 需求分析:

1. 输⼊留⾔信息, 点击提交. 后端把数据存储起来.

2. ⻚⾯展⽰输⼊的表⽩墙的信息

 接口定义

1.获取全部留言

请求

【请求路径】

/message/getList

【请求⽅式】

GET

【接⼝描述】

获取留言

响应数据

注意哦,这个是JSON格式的

[

        {

              "from": "⿊猫",

               "to": "⽩猫",

               "message": "喵"

         },{

                "from": "⿊狗",

                 "to": "⽩狗",

                 "message": "汪"

         }, //...

]

浏览器给服务器发送⼀个 GET /message/getList 这样的请求, 就能返回当前⼀共有哪些留⾔ 记录. 结果以 json 的格式返回过来. 

 2.发表留言

请求

body也为JSON格式

【请求⽅式】

POST       

【请求路径】

/message/publish

【请求参数】

{

        "from": "⿊猫",

        "to": "⽩猫",

         "message": "喵"

}

响应

{

        ok:1

}

我们期望浏览器给服务器发送⼀个 POST /message/publish 这样的请求, 就能把当前的留⾔提交给服务器. 

代码实现 

因为传递的是json对象,所以我们首先要有一个MessageInfo对象,我们直接返回。MessageInfo对象List就好了,因为Spring引入了注解,可以在return返回值的时候直接帮我们转换成Json对象。

这里有个注解是@Data,这个是引入lombok依赖,这样像这些set和get方法,它都可以自动帮我们生成。其他的只要按照接口定义来写代码就是ok的了,请看代码。

为什么这里不需要session,而上个案例要session呢?

答:因为上个案例不是同个页面,这个案例的html只有一个页面,所以不需要用session。

@RequestMapping("/message")
@RestController
public class MessageController {
    public List<MessageInfo> list=new ArrayList<>();
    @RequestMapping(value = "/getList",method = RequestMethod.GET)
    public List<MessageInfo> getList(){
        return list;
    }
    @RequestMapping(value = "/publish",method = RequestMethod.POST)
    public boolean publish(MessageInfo messageInfo){
        if(StringUtils.hasLength(messageInfo.getFrom())
                ||StringUtils.hasLength(messageInfo.getTo())
        ||StringUtils.hasLength(messageInfo.getMessage())){
            list.add(messageInfo);
            return true;
        }else return false;
    }
}


BookInfo

@Data
public class MessageInfo {
    private String from;
    private String to;
    private String message;
}

【前端】

我们有两个需要写Ajax的地方,一个是展示List,一个是发送message。

我们先看发送message,其他的都是按接口定义就能写,需要注意的是我们点击发送了之后不会直接显示值在上面,而是要点刷新,

所以我们需要写divE把它接上去,这里的值是前端的值,input输入框的值,因为后端没有传值过来,传的是true和false。

 展示List我们依旧是用的Ajax,返回来的是一个list,里面装的是很多个MessageInfo,所以我们用迭代把他们拿出来。因为后端传值过来,所以我们需要写message而不是say。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言板</title>
    <style>
        .container {
            width: 350px;
            height: 300px;
            margin: 0 auto;
            /* border: 1px black solid; */
            text-align: center;
        }

        .grey {
            color: grey;
        }

        .container .row {
            width: 350px;
            height: 40px;

            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .container .row input {
            width: 260px;
            height: 30px;
        }

        #submit {
            width: 350px;
            height: 40px;
            background-color: orange;
            color: white;
            border: none;
            margin: 10px;
            border-radius: 5px;
            font-size: 20px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>留言板</h1>
        <p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
        <div class="row">
            <span>谁:</span> <input type="text" name="" id="from">
        </div>
        <div class="row">
            <span>对谁:</span> <input type="text" name="" id="to">
        </div>
        <div class="row">
            <span>说什么:</span> <input type="text" name="" id="say">
        </div>
        <input type="button" value="提交" id="submit" onclick="submit()">
        <!-- <div>A 对 B 说: hello</div> -->
    </div>

    <script src="./js/jquery.min.js"></script>
    <script>
        $.ajax({
            type: "get",
            url: "message/getList",
            success: function (ret) {
                if (ret != null) {
                    for (var messageInfo of ret) {
                        //2. 构造节点
                        var divE = "<div>" + messageInfo.from + "对" + messageInfo.to + "说:" + messageInfo.message + "</div>";
                        //3. 把节点添加到页面上
                        $(".container").append(divE);
                    }
                }
            }
        });

        function submit() {
            //1. 获取留言的内容
            var from = $('#from').val();
            var to = $('#to').val();
            var say = $('#say').val();
            if (from == '' || to == '' || say == '') {
                return;
            }
            $.ajax({
                type: "post",
                url: "message/publish",
                data: {
                    from: from,
                    to: to,
                    message: say
                },
                success: function (ret) {
                    if (ret) {
                        alert("添加成功");
                        //2. 构造节点
                        var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
                        //3. 把节点添加到页面上    
                        $(".container").append(divE);
                    } else alert("添加失败");
                }
            });

            //4. 清空输入框的值
            $('#from').val("");
            $('#to').val("");
            $('#say').val("");

        }

    </script>
</body>

</html>

四、图书管理(综合性案例) 

需求:1. 登录: ⽤⼾输⼊账号,密码完成登录功能 2. 列表展⽰: 展⽰图书

需求分析

1.用户登录

【URL】

POST /user/login

【请求参数】

name=admin&password=admin

【响应】

true //账号密码验证成功

false//账号密码验证失败

2.图书列表

【URL】

POST /book/getList

【 请求参数 】

【 响应 】

返回图书列表

[

        {

                 "id": 1,

                 "bookName": " 活着 ",

                 "author": " 余华 ",

                 "count": 270,

                 "price": 20,

                 "publish": " 北京⽂艺出版社 ",

                 "status": 1,

                 "statusCN": " 可借阅 "

        },

          ...

]

字段说明

id 图书id
bookName 图书名称
author 作者
count 数量
publish 图书出版社
price 定价
status 图书状态 1-可借阅 0-不可借阅
statusCN 图书状态中文含义

【后端】

UserController和BookInfo咱们就不说了,没啥含金量

ListController中我们有个mockList方法,这是一个伪造数据,很常用,因为我们现在没有数据库来调用,所以我们先自己伪造一些数据。

BookInfo
@Data
public class BookInfo {
    private Integer id;
    private String name;
    private String author;
    private Integer number;
    private BigDecimal price;
    private String publish;
    private String publishCN;
    private Integer status;
}


UserController
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public boolean login(String name,String password){
        if(StringUtils.hasLength(name)&&StringUtils.hasLength(password)){
            if("admin".equals(name)&&"admin".equals(password)){
                return true;
            }
        }
        return false;
    }
}



ListController
@RestController
@RequestMapping("book")
public class ListController {
    @RequestMapping(value = "/getList",method = RequestMethod.POST)
    public List<BookInfo> getList(){
        List<BookInfo> list=mockList();
        for(BookInfo info:list){
            if(info.getStatus()==1){
                info.setPublishCN("可借阅");
            }else info.setPublishCN("不可借阅");
        }
        return list;
    }

    private List<BookInfo> mockList() {
        List<BookInfo> list=new ArrayList<>();
        for(int i=1;i<=15;i++){
            BookInfo info=new BookInfo();
            info.setId(i);
            info.setName("书名"+i);
            info.setAuthor("作者"+i);
            info.setNumber(new Random().nextInt(70));
            info.setPrice(new BigDecimal(new Random().nextInt(70)+10));
            info.setPublish("出版社"+i);
            info.setStatus(i%5);
            list.add(info);
        }
        return list;
    }
}

【前端】

login.html前面的案例经常有,我们就跳过了。

book_list.html,我们看Ajax的请求,与之前案例不一样的是,我们捏造的数据需要传到页面上去,每一条都要捏造,所以我们用字符串拼接的形式,最后html填到tbody上。

如果是text的话,就只有文字,css那些显示不出来。location.href=""是前端要跳转url的函数。

login.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/login.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
</head>

<body>
    <div class="container-login">
        <div class="container-pic">
            <img src="pic/computer.png" width="350px">
        </div>
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <input type="text" name="userName" id="userName" class="form-control">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" name="password" id="password" class="form-control">
            </div>
            <div class="row">
                <button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
            </div>
        </div>
    </div>
    <script src="js/jquery.min.js"></script>
    <script>
        function login() {
            $.ajax({
                type: "post",
                url: "user/login",
                data: {
                    name: $("#userName").val(),
                    password: $("#password").val()
                },
                success: function (ret) {
                    if (ret) {
                        location.href = "book_list.html";
                    } else {
                        alert("密码或用户名错误");
                    }
                }
            });

        }
    </script>
</body>

</html>



book_list.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书列表展示</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">

    <link rel="stylesheet" href="css/list.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <script src="js/jq-paginator.js"></script>

</head>

<body>
    <div class="bookContainer">
        <h2>图书列表展示</h2>
        <div class="navbar-justify-between">
            <div>
                <button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
                <button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
            </div>
        </div>

        <table>
            <thead>
                <tr>
                    <td>选择</td>
                    <td class="width100">图书ID</td>
                    <td>书名</td>
                    <td>作者</td>
                    <td>数量</td>
                    <td>定价</td>
                    <td>出版社</td>
                    <td>状态</td>
                    <td class="width200">操作</td>
                </tr>
            </thead>
            <tbody id="tbody">

            </tbody>
        </table>

        <div class="demo">
            <ul id="pageContainer" class="pagination justify-content-center"></ul>
        </div>
        <script>

            getBookList();
            function getBookList() {
                $.ajax({
                    type: "post",
                    url: "book/getList",
                    success: function (ret) {
                        if (ret != null) {
                            var finalHtml = "";
                            for (var bookinfo of ret) {
                                finalHtml += '<tr>';
                                finalHtml += '<td><input type="checkbox" name="selectBook" value="' + bookinfo.id + '" id="selectBook" class="book-select"></td>';
                                finalHtml += '<td>' + bookinfo.id + '</td>';
                                finalHtml += '<td>' + bookinfo.name + '</td>';
                                finalHtml += '<td>' + bookinfo.author + '</td>';
                                finalHtml += '<td>' + bookinfo.number + '</td>';
                                finalHtml += '<td>' + bookinfo.price + '</td>';
                                finalHtml += '<td>' + bookinfo.publish + '</td>';
                                finalHtml += '<td>' + bookinfo.publishCN + '</td>';
                                finalHtml += '<td>';
                                finalHtml += '<div class="op">';
                                finalHtml += '<a href="book_update.html?bookId=' + bookinfo.id + '">修改</a>';
                                finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + bookinfo.id + ')">删除</a>';
                                finalHtml += '</div>';
                                finalHtml += '</td>';
                                finalHtml += '</tr>';
                            }
                            $("#tbody").html(finalHtml);
                        }
                    }
                });
            }

            //翻页信息
            $("#pageContainer").jqPaginator({
                totalCounts: 100, //总记录数
                pageSize: 10,    //每页的个数
                visiblePages: 5, //可视页数
                currentPage: 1,  //当前页码
                first: '<li class="page-item"><a class="page-link">首页</a></li>',
                prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
                next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
                last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
                page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                //页面初始化和页码点击时都会执行
                onPageChange: function (page, type) {
                    console.log("第" + page + "页, 类型:" + type);
                }
            });
            function deleteBook(id) {
                var isDelete = confirm("确认删除?");
                if (isDelete) {
                    //删除图书
                    alert("删除成功");
                }
            }
            function batchDelete() {
                var isDelete = confirm("确认批量删除?");
                if (isDelete) {
                    //获取复选框的id
                    var ids = [];
                    $("input:checkbox[name='selectBook']:checked").each(function () {
                        ids.push($(this).val());
                    });
                    console.log(ids);
                    alert("批量删除成功");
                }
            }

        </script>
    </div>
</body>

</html>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐