跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Java大前端java

SpringMVC 企业级开发实战:制作简单小网页

通过计算器、用户登录、留言板及图书管理系统雏形四个案例,演示了 SpringMVC 前后端交互接口的定义与实现。内容涵盖 GET/POST 请求处理、Session 会话管理、JSON 数据交互以及基础 CRUD 逻辑。重点讲解了 Controller 层编写、参数接收方式及前端 AJAX 调用流程,帮助开发者快速上手企业级 Web 项目开发流程。

imJackJia发布于 2026/2/6更新于 2026/7/175.4K 浏览
SpringMVC 企业级开发实战:制作简单小网页

引言

经过了前面几节课夯实的基础,相信大家对于使用 SpringMVC 进行开发有了深刻的理解,一定迫不及待想要自己上手开发独属于自己的小项目了!这节课我将带着大家从零开始做一些简单的小网页。

前后端交互接口

概念理解

接口又叫 API,一般来说接口和 API 指的都是同一个东西。是指应用程序对外提供的服务的描述,用于交换信息和执行任务(跟 JavaSE 类和接口的接口不一样!)。简单来说就是允许客户端给服务器发送哪些 HTTP 请求,并且每种请求预期获取什么样的 HTTP 响应。

前后端分离开发背景下,前端和后端代码通常由不同团队进行开发。双方在开发前会提前约定好交互的方式。把约定的内容写在文档上,就是'接口文档',可以理解为是应用程序的操作说明书。

例如:玩游戏时,按哪个键会产生什么反应,比如无畏契约按 4 拆包等。这些说明一般都会有一些文档或者网页来进行说明,这些按键就是接口,说明书就是接口文档

在项目开发前,根据需求先约定好前后端交互接口,双方按照接口文档进行开发。

实操

需求分析 以一个简单的计算器为例:加法计算器功能,对两个整数进行相加,需要客户端提供参与计算的两个数,服务端返回这两个整数计算的结果。

接口定义

请求路径:calc/sum
请求方式:GET/POST
接口描述:计算两个整数相加

请求参数

在这里插入图片描述

响应数据

Content-Type: text/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>
</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>

后端代码:

package com.bite.spring.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/calc")
public class CalcController {
    @RequestMapping("/sum")
    public String sum(Integer num1, Integer num2) {
        Integer sum = num1 + num2;
        return "<h1> 相加的结果是:" + sum + "</h1>";
    }
}

在这里插入图片描述

在这里插入图片描述

输入两个数字后,点击相加,前端会触发提交操作,将这些信息提交并转到 calc/sum 页面。

用户登录

需求:用户输入账号和密码,后端进行校验密码是否正确。

  1. 如果不正确,前端进行用户告知。
  2. 如果正确,跳转到首页。首页显示当前登录用户。
  3. 后续再访问首页,可以获取到登录用户信息。

需求分析 对于后端开发人员而言,不涉及前端页面的展示,只需要提供两个功能:

  1. 登录页面:通过账号和密码,校验输入的账号密码是否正确,并告知前端。
  2. 首页:告知前端当前登录用户,如果当前已有用户登录,返回登录的账号,如果没有,返回空。

1. 检验接口

请求路径:/user/login
请求方式:POST
接口描述:校验账号密码是否正确

在这里插入图片描述

响应数据 Content-Type:text/html 内容:true/false

2. 查询用户登录接口

请求路径:/user/getLoginUser
请求方式:GET
接口描述:查询当前登录的用户

无请求参数

响应: Content-Type: text/html 响应内容:zhangsan

代码展示

后端代码:

package com.bite.spring.demo;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.val;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class LoginController {
    @RequestMapping("/login")
    public Boolean login(String userName, String password, HttpSession session) {
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
            return false;
        }
        if (userName.equals("admin") && password.equals("admin")) {
            session.setAttribute("userName", userName);
            return true;
        } else {
            return false;
        }
    }

    @RequestMapping("/getLoginUser")
    public String returnUserName(HttpSession session) {
        String userName = (String) session.getAttribute("userName");
        return userName;
    }
}

前端代码:

登录:

<!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="/jquery-3.7.1.min.js"></script>
<script>
function login() {
    $.ajax({
        type: "post",
        url: "/user/login",
        data: {
            userName: $("#userName").val(),
            password: $("#password").val()
        },
        success: function(result) {
            if (result) {
                location.href = "index.html";
            } else {
                alert("密码错误,请确认");
            }
        }
    });
}
</script>
</body>
</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="jquery-3.7.1.min.js"></script>
<script>
$.ajax({
    url: "/user/getLoginUser",
    type: "get",
    success: function(userName) {
        $("#loginUser").text(userName);
    }
});
</script>
</body>
</html>

在这里插入图片描述

在这里插入图片描述

总体的代码运行逻辑:

  1. 访问 login.html 界面,输入用户名密码。
  2. login 使用 ajax 跳转到后端 user/login 接口,接口接收用户名密码数据。
  3. 检测之后返回检测结果。
  4. login.html 根据结果判断是否跳转到 index.html 界面。
  5. 跳转后,输出结果。

小 tips:此处将 userName 存储到 Session 中,这样无需显示传参就可以在 index.html 界面得到 userName 的值了。

留言板

需求 输入留言信息,点击提交。后端把数据存储起来。页面展示输入的信息。

在这里插入图片描述

需求分析 后端需要提供两个服务:

  1. 提交留言:用户输入留言信息之后,后端需要把留言信息保存起来。
  2. 展示留言:页面展示时,需要从后端获取到所有的留言信息。

接口 1. 获取全部留言: GET /message/getList 响应:返回 JSON

接口 2. 发表新留言: POST /message/publish 请求:body 也是 JSON 格式

代码部分

后端代码:

package com.bite.spring.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/message")
public class MessageController {
    private List<MessageInfo> messageInfoList = new ArrayList<>();

    @PostMapping(value = "/publish")
    public String publish(@RequestBody MessageInfo messageInfo) {
        if (!StringUtils.hasLength(messageInfo.getFrom()) || !StringUtils.hasLength(messageInfo.getTo()) || !StringUtils.hasLength(messageInfo.getMessage())) {
            return "{\"ok\": 0}";
        }
        // 存储留言
        messageInfoList.add(messageInfo);
        return "{\"ok\": 1}";
    }

    @GetMapping("/getList")
    public List<MessageInfo> getList() {
        return messageInfoList;
    }
}

前端代码:

<!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: auto; margin:0 auto; 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: #f8c203; color: white; border: none; margin:10px; border-radius:5px; font-size:20px; cursor: pointer; }
.message-item { margin:8px 0; padding:5px; border-bottom:1px solid #eee; }
</style>
</head>
<body>
<div class="container">
<h1>留言板</h1>
<p class="grey">输入后点击提交,会将信息显示下方空白处</p>
<div class="row"><span>谁:</span><input type="text" name="" id="from" placeholder="请输入留言人"></div>
<div class="row"><span>对谁:</span><input type="text" name="" id="to" placeholder="请输入接收人"></div>
<div class="row"><span>说什么:</span><input type="text" name="" id="say" placeholder="请输入留言内容"></div>
<input type="button" value="提交" id="submit" onclick="submitMessage()">
<div id="messageList" style="margin-top: 20px;"></div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
// 页面加载时获取留言列表
loadMessageList();

function loadMessageList() {
    $.ajax({
        type: "get",
        url: "/message/getList",
        success: function(messages) {
            if (messages && messages.length > 0) {
                var finalHtml = "";
                for (var m of messages) {
                    finalHtml += `<div class="message-item">${m.from} 对 ${m.to} 说:${m.message}</div>`;
                }
                $("#messageList").html(finalHtml);
            }
        },
        error: function(xhr, status, error) {
            console.error("加载留言失败:", status, error);
            alert("加载留言列表失败,请检查后端服务是否启动");
        }
    });
}

function submitMessage() {
    var from = $('#from').val().trim();
    var to = $('#to').val().trim();
    var say = $('#say').val().trim();

    if (from === '') {
        alert("请输入留言人!"); $('#from').focus(); return;
    }
    if (to === '') {
        alert("请输入接收人!"); $('#to').focus(); return;
    }
    if (say === '') {
        alert("请输入留言内容!"); $('#say').focus(); return;
    }

    var data = { from: from, to: to, message: say };

    $.ajax({
        type: "post",
        url: "/message/publish",
        contentType: "application/json",
        data: JSON.stringify(data),
        success: function(result) {
            if (result.ok === 1) {
                var newMessage = `<div class="message-item">${from} 对 ${to} 说:${say}</div>`;
                $("#messageList").append(newMessage);
                $('#from').val(""); $('#to').val(""); $('#say').val("");
            } else {
                alert("留言发布失败,请重试!");
            }
        },
        error: function(xhr, status, error) {
            console.error("提交失败:", xhr.status, error, xhr.responseText);
            alert(`提交失败!错误码:${xhr.status},请检查后端服务是否启动`);
        }
    });
}
</script>
</body>
</html>

图书管理系统(雏形)

注:目前这个代码只能完成登录和生成图书馆两个简单的功能,但是图书管理系统在接下来的博客中会反复出现。最终,我会做出一个完整的、功能多样的、符合企业级开发的管理系统。

后端代码:

package com.hbu.book;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("book")
public class BookController {
    @RequestMapping("/getList")
    public List<BookInfo> getList() {
        List<BookInfo> books = mockData();
        for (BookInfo book : books) {
            if (book.getStatus() == 1) {
                book.setStatusCN("可借阅");
            } else {
                book.setStatusCN("不可借阅");
            }
        }
        return books;
    }

    public List<BookInfo> mockData() {
        List<BookInfo> books = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            BookInfo book = new BookInfo();
            book.setId(i);
            book.setBookName("书籍" + i);
            book.setAuthor("作者" + i);
            book.setCount(i * 5 + 3);
            book.setPrice(new BigDecimal(new Random().nextInt(100) + 1));
            book.setPublish("出版社" + i);
            book.setStatus(1);
            books.add(book);
        }
        return books;
    }
}
package com.hbu.book;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public Boolean login(String name, String password) {
        if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)) {
            return false;
        }
        if ("admin".equals(name) && "admin".equals(password)) {
            return true;
        }
        return false;
    }
}

前端代码:

<!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><!-- 动态填充 --></tbody>
</table>
<div class="demo"><ul id="pageContainer" class="pagination justify-content-center"></ul></div>
<script>
getBookList();
function getBookList() {
    $.ajax({
        type: "get",
        url: "/book/getList",
        success: function(result) {
            console.log(result);
            if (result != null) {
                var finalHtml = "";
                for (var book of result) {
                    finalHtml += '<tr>';
                    finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="selectBook" class="book-select"></td>';
                    finalHtml += '<td>' + book.id + '</td>';
                    finalHtml += '<td>' + book.bookName + '</td>';
                    finalHtml += '<td>' + book.author + '</td>';
                    finalHtml += '<td>' + book.count + '</td>';
                    finalHtml += '<td>' + book.price + '</td>';
                    finalHtml += '<td>' + book.publish + '</td>';
                    finalHtml += '<td>' + book.statusCN + '</td>';
                    finalHtml += '<td><div class="op">';
                    finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';
                    finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')"> 删除 </a>';
                    finalHtml += '</div></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) {
        var ids = [];
        $("input:checkbox[name='selectBook']:checked").each(function() {
            ids.push($(this).val());
        });
        console.log(ids);
        alert("批量删除成功");
    }
}
</script>
</div>
</body>
</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(result) {
            if (result) {
                location.href = "book_list.html";
            } else {
                alert("账号或密码不正确!");
            }
        }
    });
}
</script>
</body>
</html>

在这里插入图片描述

在这里插入图片描述

目录

  1. 引言
  2. 前后端交互接口
  3. 概念理解
  4. 实操
  5. 相加计算器
  6. 用户登录
  7. 1. 检验接口
  8. 2. 查询用户登录接口
  9. 代码展示
  10. 留言板
  11. 代码部分
  12. 图书管理系统(雏形)
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Java 的在线拍卖系统设计与实现
  • Linux Camera 驱动开发:FPGA 与 SoC 对比分析
  • 二分答案专题实战:木材加工与砍树问题解析
  • OpenClaw macOS 环境搭建与安装指南
  • Claude Skills 实战:自动化工作流与技能管理
  • 大模型微调工具推荐:LLaMA-Factory 使用指南
  • VSCode AI Copilot 自定义指令配置实战指南
  • C++ 原子操作 compare_exchange_weak 详解
  • Linux 环境下的 Git 版本控制实战指南
  • OpenClaw 实现 Gateway+Node 健康检查及飞书消息推送方案
  • 5 款零配置 AI 写作镜像推荐:低成本快速体验
  • Python YAML 模块使用教程:接口测试参数存储与配置
  • 【2026必看 AI智能体】零基础Coze平台使用教程
  • 低空经济驱动下无人机光伏巡检技术革新
  • MySQL 分库分表实战:垂直水平拆分策略与核心难题解决
  • Kafka 核心架构与分布式存储
  • Claude Skills 实战:自动化工作流与前端设计生成
  • AI 产品经理薪资趋势与核心面试指南
  • C 语言 Web 开发:CGI、FastCGI、Nginx 深度解析
  • 反无人机技术原理与反制手段详解

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online