【SpringMVC】万字带你用4个项目打通SpringMVC任督二脉!


目录

1.前言

2.正文

2.1计算器

2.1.1约定前后端接口

2.1.2核心代码讲解

2.2登陆页面

2.2.1约定前后端接口

2.2.2后端核心代码讲解

2.2.3介绍Ajax

2.2.4前端核心代码讲解

2.3留言板

2.3.1约定前后端接口

2.3.2介绍Lombok

3. 常见注解及其用法

2.3.3后端核心代码讲解

2.3.4前端核心代码讲解

2.4图书管理系统

2.4.1约定前后端接口

2.4.2后端核心代码讲解

2.4.3前端核心代码讲解

3.小结


1.前言

"学习完SpringMVC的理论知识后,如何真正掌握它的核心用法?"本文将通过4个由浅入深的综合案例,其中包括简单计算器,登陆页面,留言板,简单图书管理系统。并在最后介绍下应用分层,那么话不多说让我们开始吧。

2.正文

在正式讲解之前,所有的源代码都在博主本人的gitee中,网址附上:

爱吃烤鸡翅的酸菜鱼 (crjs-hao) - Gitee.com https://gitee.com/crjs-hao

2.1计算器

2.1.1约定前后端接口

介绍API文档:

一份完整的API文档需要清晰描述接口功能、使用方法和约束条件,通常包含以下核心模块:

  • API名称:简明扼要的功能描述(如“用户登录接口”)。

  • 版本号:标识当前API版本(目前咱们用不到)。

  • 接口描述:功能用途、适用场景、特殊限制(如权限要求)。

  • URL地址:完整的请求路径(如https://api.example.com/v1/user/login)。

  • 请求方法:GET、POST、PUT、DELETE等。


 简单介绍完后,我们开始写我们当前的API文档: 

接口定义:

请求路径:calc/sum

请求方式:GET/POST

接口描述:计算两个数加和

请求参数:

参数名类型是否必须备注
num1Integer参与计算的第一个数
num2Interger参与计算的第二个数

响应数据:

Content-Type: text/html

response:计算结果为:..

2.1.2核心代码讲解

@RequestMapping("/calc")
@RestController
public class CalcController {
    @RequestMapping("/sum")
    public String sum(Integer num1,Integer num2){
        if(num1 == null || num1 == null){
            return "参数非法";
        }
        Integer sum = num1 + num2;
        return "<h1>计算结果: " + sum + "</h1>";
    }
}
  • 核心逻辑:接收两个整数参数 num1 和 num2,返回它们的和。

  • 请求路径

    • 类级别路径:/calc

    • 方法级别路径:/sum

    • 完整访问路径:http://localhost:8080/calc/sum?num1=10&num2=20

  • 返回结果

    • 成功:HTML 格式的字符串(如 <h1>计算结果: 30</h1>)。

    • 失败:参数为 null 时返回 "参数非法"

<!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>
  • 功能:实现一个简单的网页计算器,用于输入两个数字并相加。

  • 表单

    • 包含两个输入框,分别用于输入数字1和数字2。

    • 提交按钮触发表单提交。

  • 提交方式

    • 使用POST方法将数据发送到服务器的calc/sum路径。

  • 处理逻辑

    • 服务器接收num1num2参数,进行相加操作。

    • 返回计算结果。

运行结果:

 

2.2登陆页面

2.2.1约定前后端接口

接口定义:

请求路径:/user/login

请求方式:POST

接口描述:校验账号密码是否正确

请求参数:

参数名类型是否必须备注
userNameString校验的账号
passwordString校验的密码

响应数据:

Content-Type: text/html

响应内容:

2.2.2后端核心代码讲解

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public boolean login(String name, String password, HttpSession session){
        if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
            return false;
        }

        if("admin".equals(name) && "admin".equals(password)){
            session.setAttribute("name",name);
            return true;
        }
        return false;
    }

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

 

  • 类定义

    • 类名为UserController

    • 使用@RestController注解,表示这是一个RESTful控制器。

    • 使用@RequestMapping("/user")注解,将类中的方法映射到/user路径下。

  • 方法定义

    • login方法:

      • 映射到/user/login路径。

      • 接受用户名(name)和密码(password)作为参数。

      • 检查用户名和密码是否为空。

      • 如果用户名和密码都为admin,则将用户名存入会话(session)并返回true

      • 否则返回false

    • getLoginUser方法:

      • 映射到/user/getLoginUser路径。

      • 从会话中获取存储的用户名并返回。

  • 功能

    • 提供用户登录功能,验证用户名和密码。

    • 获取当前登录用户的用户名。

2.2.3介绍Ajax

在正式讲解前端代码前,需要先介绍下js中的Ajax:

AJAX - MDN Web 文档术语表:Web 相关术语的定义 | MDNAJAX(Asynchronous JavaScript And XML)是一种在 Web 应用中通过异步发送 HTTP 请求向服务器获取内容,并使用这些新内容更新页面中相关的部分,而无需重新加载整个页面的 Web 开发技术。这可以让网页更具有响应性,因为只请求了需要更新的部分。 https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX

 

1. 什么是Ajax?

定义:Ajax是异步JavaScript和XML,其是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行数据交换,实现页面的异步更新。

2. Ajax的工作原理

  • 用户在网页上触发某个事件(如点击按钮、输入文本等)。
  • JavaScript通过XMLHttpRequest对象向服务器发送异步请求。
  • 服务器接收到请求后,处理数据并返回响应。
  • JavaScript接收服务器响应,并根据返回的数据更新网页内容。

5. Ajax的基本流程

创建XMLHttpRequest对象

  • 用于与服务器进行通信。

配置请求

  • 指定请求方法(如GETPOST)和URL。

设置请求头(可选)

  • 定义请求的内容类型等信息。

发送请求

  • 使用send()方法发送请求,可以附带请求数据(如表单数据)。

处理响应

  • 通过监听onreadystatechange事件或使用fetch.then()方法,处理服务器返回的数据。

下文会有详细的Ajax代码的展示。 

2.2.4前端核心代码讲解

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="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script>
        $.ajax({
            url: "/user/getLoginUser",
            type: "get",
            success: function(name){
                $("#loginUser").text(name);
            }

        });
    </script>
</body>

</html>
  • 功能:实现一个简单的用户登录状态显示功能,用于在网页上显示当前登录的用户名。

  • 表单

    • 页面上有一个<span>元素,用于显示用户名。

    • 无需用户输入,直接通过AJAX从服务器获取用户名。

  • 提交方式

    • 使用GET方法将请求发送到服务器的/user/getLoginUser路径。

  • 处理逻辑

    • 服务器接收请求,查询当前登录的用户名。

    • 返回查询到的用户名。

login.html:

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

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

<body>
  <h1>用户登录</h1>
  用户名:<input name="name" type="text" id="name"><br>
  密码:<input name="password" type="password" id="password"><br>
  <input type="button" value="登录" onclick="login()">
  
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
  <script>
              function login(){
                  $.ajax({
                      type: "post",
                      url: "/user/login",
                      data: {
                          name: $("#name").val(),
                          password: $("#password").val()
                      },
                      success: function(result){
                          if(result){
                              //true
                              location.href = "index.html";
                          }else{
                              //false
                              alert("密码错误,请确认")
                          }
                      }
                  })
              }
          </script>
</body>

</html>
  • 功能:实现一个简单的用户登录页面,用户输入用户名和密码后点击登录按钮进行验证。

  • 表单

    • 包含两个输入框,分别用于输入用户名和密码。

    • 包含一个按钮,点击后触发登录操作。

  • 提交方式:使用POST方法将数据发送到服务器的/user/login路径。

  • 处理逻辑

    • 服务器接收namepassword参数,进行登录验证。

    • 返回验证结果。

运行结果: 

2.3留言板

2.3.1约定前后端接口

接口1:获取全部留言:

请求:

GET/message/getList

响应:JSON格式

[
    {
        "from": "tom",
        "to": "kerry",
        "message": "hello"
    }
]

接口2:发表新留言: 

请求:

POST/message/publish

{
        "from": "tom",
        "to": "kerry",
        "message": "hello"
    }

响应:JSON

{
   ok: 1
}

2.3.2介绍Lombok

我们在写代码的时候发现,如果每一次创建对象时都要写构造方法以及成员变量的相关方法,将会让代码显得十分臃肿,于是乎我们就引入了个工具——Lombok。


Lombok 是一种 Java 库,通过注解的形式简化 Java 代码,减少样板代码(boilerplate code)的编写。它可以自动为类生成 getter 和 setter 方法、构造函数、equals 和 hashCode 方法等。以下是 Lombok 的详细介绍及其常见注解的用法:

1. Lombok 的核心优势

  • 减少样板代码:自动生成 getter/setter、构造函数、toString 等方法,避免手动编写重复代码。

  • 提高开发效率:专注于业务逻辑,减少机械性的代码输入。

  • 增强代码可读性:代码更简洁,逻辑更清晰。

  • 与 IDE 集成良好:支持主流 IDE(如 IntelliJ IDEA、Eclipse 等),提供实时代码补全和错误检查。


2. Lombok 的安装与配置

需要在maven中配置好相关信息:

<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.30</version>
			<scope>provided</scope>
		</dependency>

记得刷新maven,重启项目。


3. 常见注解及其用法

@Getter 和 @Setter

  • 自动生成类属性的 getter 和 setter 方法。

  • 可以对单个属性或整个类应用。

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class User {
    private String name;
    private int age;
}

@ToString

 

  • 自动生成 toString() 方法,默认包含所有字段。

  • 可通过 exclude 属性排除特定字段。

import lombok.ToString;

@ToString(exclude = "id")
public class User {
    private Long id;
    private String name;
    private int age;
}

@EqualsAndHashCode

  • 自动生成 equals()hashCode() 方法,默认比较所有字段。

  • 支持 exclude 属性排除特定字段。

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude = "age")
public class User {
    private String name;
    private int age;
}

@Data

  • 综合注解,等同于 @Getter + @Setter + @ToString + @EqualsAndHashCode + @AllArgsConstructor

  • 适用于简单的 POJO(Plain Old Java Object)类。

import lombok.Data;

@Data
public class User {
    private String name;
    private int age;
}

操作示例:

package com.example.demo;

import lombok.Data;

@Data
public class MessageInfo {
    private String From;
    private String To;
    private String Message;
}

我去target文件中去寻找编译后的文件:

2.3.3后端核心代码讲解

@RequestMapping("/message")
@RestController
public class messageController {

    private final List<MessageInfo> messageInfoList = new ArrayList<>();

    @PostMapping(value = "/publish",produces = "application/json")
    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;
    }
}
  • 类定义:定义了一个名为 messageController 的类,使用 @RestController 注解,标识这是一个控制器类。

  • 成员变量:声明了一个 messageInfoList 列表,用于存储 MessageInfo 对象。

  • publish 方法

    • 使用 @PostMapping 注解映射 HTTP POST 请求到 /publish 路径。

    • 接收一个 JSON 格式的 MessageInfo 对象,并检查其 fromtomessage 属性是否非空。

    • 如果检查通过,将 MessageInfo 对象添加到 messageInfoList 列表中,并返回 {"ok": 1} 表示成功。

    • 如果检查不通过,返回 {"ok": 0} 表示失败。

  • getList 方法

    • 使用 @GetMapping 注解映射 HTTP GET 请求到 /getList 路径。

    • 返回 messageInfoList 列表中的所有 MessageInfo 对象。

2.3.4前端核心代码讲解

<script>
        load();

		function load(){
			$.ajax({
			type: "get",
			url: "/message/getList",
			success: function(messages){
				if(messages != null && messages.length > 0){
					var finalHtml = "";
					for(var m of messages){
						var item = "<div>"+m.from +"对" + m.to + "说:" + m.message+"</div>"
						finalHtml += item;
					}
					$(".container").append(finalHtml);
					}
				}
			});
		}

        function submit(){
            //1. 获取留言的内容
            var from = $('#from').val();
            var to = $('#to').val();
            var say = $('#say').val();
            if (from== '' || to == '' || say == '') {
                return;
            }
            var data = {
					from: from,
					to: to,
					message: say
				};

            $.ajax({
				type: "post",
				url: "/message/publish",
				data: JSON.stringify(data),
				contentType: "application/json",
				success: function(result){
					if(result.ok == 1){
						//yes
						//2. 构造节点
						var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
						//3. 把节点添加到页面上
						$(".container").append(divE);

						//4. 清空输入框的值
						$('#from').val("");
						$('#to').val("");
						$('#say').val("");
					}else{
						//no
						alert("留言发布失败");
					}
				}
			});
        }
    </script>
  • 功能:实现留言板功能,用户输入留言并提交,成功后留言显示在页面上。

  • load 函数

    • 发起 GET 请求到 /message/getList 获取留言列表。

    • 如果获取到留言列表,遍历列表生成 HTML 元素,并追加到页面的 .container 元素中。

  • submit 函数

    • 获取用户输入的留言内容(留言人、收件人、留言内容)。

    • 检查输入框是否为空,为空则不执行操作。

    • 将留言内容封装成 JSON 数据格式,发起 POST 请求到 /message/publish

    • 请求成功且服务器返回 ok1 时,将留言内容添加到页面 .container 元素中,并清空输入框。

    • 如果请求失败,弹出警告框提示“留言发布失败”。

运行结果:

 

2.4图书管理系统

2.4.1约定前后端接口

接口1:登录接口

  • URLPOST /user/login

  • 请求参数

    • name=admin & password=admin

  • 响应

    • true // 账号密码验证成功

    • false // 账号密码验证失败

接口2:图书列表展示

  • URLPOST /book/getList

  • 请求参数:无

  • 响应:返回图书列表:

    [
    {
    "id": 1,
    "bookName": "活着",
    "author": "余华",
    "count": 270,
    "price": 20,
    "publish": "北京文艺出版社",
    "status": 1,
    "statusCN": "可借阅"
    },
    ...
    ]

2.4.2后端核心代码讲解

代码分配:

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public boolean login (String name, String password, HttpSession session){
        if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
            return false;
        }

        if("admin".equals(name) && "admin".equals(password)){
            session.setAttribute("userName", name);
            return true;
        }
        return false;
    }
    
}
  • 类定义:定义了一个名为 UserController 的类,并使用 @RestController 注解,标识这是一个控制器类。

  • 方法 login

    • 使用 @RequestMapping("/login") 注解映射 HTTP POST 请求到 /user/login 路径。

    • 接收用户名 (name) 和密码 (password) 作为参数,并使用 HttpSession 存储会话信息。

    • 检查用户名和密码是否非空。

    • 如果用户名和密码都是 "admin",则将用户名存储在会话中,并返回 true 表示登录成功。

    • 如果用户名或密码不匹配,则返回 false 表示登录失败。

@RequestMapping("/book")
@RestController
public class BookController {
    @RequestMapping("/getList")
    public List<BookInfo> getList(){
        //mock数据
        List<BookInfo> bookInfos = mockData();

        for (BookInfo bookInfo : bookInfos){
            if(bookInfo.getStatus() == 1){
                bookInfo.setStatusCN("可借阅");
            }else{
                bookInfo.setStatusCN("不可借阅");
            }
        }
        return bookInfos;
    }

    public List<BookInfo> mockData(){
        List<BookInfo> bookInfos = new ArrayList<>();
        for(int i = 1;i <= 15;i++){
            BookInfo bookInfo = new BookInfo();
            bookInfo.setBookid(i);
            bookInfo.setBookname("book" + i);
            bookInfo.setAuthor("author" + i);
            bookInfo.setPublish("publish" + i);
            bookInfo.setNum(new Random().nextInt(100));
            bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
            bookInfo.setStatus(i % 5 == 0 ? 2 : 1);//1可借阅,2不可借阅
            bookInfos.add(bookInfo);
        }
        return bookInfos;
    }
}
  • 类定义:定义了一个名为 BookController 的类,并使用 @RestController 注解,标识这是一个控制器类。

  • 方法 getList

    • 使用 @RequestMapping("/getList") 注解映射 HTTP 请求到 /book/getList 路径。

    • 返回一个 BookInfo 对象的列表,表示图书列表。

    • 列表中的每个 BookInfo 对象根据其 status 属性设置 statusCN 属性为 "可借阅" 或 "不可借"。

  • 方法 mockData

    • 用于生成模拟图书数据。

    • 创建一个包含15个 BookInfo 对象的列表,每个对象的属性使用循环变量 i 和随机数生成。

    • 将生成的 BookInfo 对象添加到列表中并返回。

2.4.3前端核心代码讲解

<script>
        function add() {
            //请求后端
			$.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>
  • 功能:实现用户登录功能,提交用户名和密码到服务器进行验证。

  • 请求方式:使用POST方法将数据发送到服务器的/user/login路径。

  • 数据:从页面上的userNamepassword输入框中获取用户名和密码。

  • 成功处理:如果服务器返回true(账号密码验证成功),则跳转到book_list.html页面。

  • 失败处理:如果服务器返回false(账号密码验证失败),则弹出警告框提示“账号或密码有误”。

<script>

            getBookList();
            function getBookList() {
                $.ajax({
					type: "get",
					url: "/book/getList",
					success:function(books){
						var finalHtml = "";
						for(var book of books){
							finalHtml += '<tr>';
							finalHtml += '<td><input type="checkbox" name="selectBook" value="'+ book.bookid +'" id="selectBook" class="book-select"></td>';
							finalHtml += '<td>'+book.bookid+'</td>';
							finalHtml += '<td>'+book.bookname+'</td>';
							finalHtml += '<td>'+book.author+'</td>';
							finalHtml += '<td>'+book.num+'</td>';
							finalHtml += '<td>'+book.price+'</td>';
							finalHtml += '<td>'+book.publish+'</td>';
							finalHtml += '<td>'+book.statusCN+'</td>';
							finalHtml += '<td>';
							finalHtml += '<div class="op">';
							finalHtml += '<a href="book_update.html?bookId='+book.bookid+'">修改</a>';
							finalHtml += '<a href="javascript:void(0)" onclick="deleteBook('+book.bookid+')">删除</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>
  • 功能:从服务器获取图书列表并在网页上显示,提供分页功能和删除图书功能。

  • AJAX请求

    • 使用GET方法请求/book/getList路径获取图书列表。

  • 成功后,遍历图书列表,为每本图书生成HTML表格行,并更新到页面的<tbody>元素中。

  • 分页功能

    • 使用.jqPaginator插件实现分页功能。

    • 配置总记录数、每页记录数、可视页数等参数。

    • 为分页组件的导航按钮(首页、上一页、下一页、最后一页)和页码项设置点击事件处理器,点击时打印当前页码和类型。

  • 删除图书

    • deleteBook函数:弹出确认对话框询问用户是否删除图书,如果用户确认,则显示删除成功的提示。

    • batchDelete函数:弹出对话框询问用户是否批量删除选中的图书,如果用户确认,则获取所有选中的图书ID并打印到控制台,显示批量删除成功的提示。

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,需要所有的源代码可以去我的gitee上就可以啦~你的支持就是对我最大的鼓励,大家加油!

爱吃烤鸡翅的酸菜鱼 (crjs-hao) - Gitee.com https://gitee.com/crjs-hao

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃烤鸡翅的酸菜鱼

希望大家对我多多支持喔~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值