【Java EE】Spring Web MVC入门:综合实践与架构设计

文章目录

  • 一、综合性练习
    • [1.1 加法计算器](#1.1 加法计算器)
      • [1.1.1 需求与准备](#1.1.1 需求与准备)
      • [1.1.2 前后端交互接口约定](#1.1.2 前后端交互接口约定)
      • [1.1.3 代码实现](#1.1.3 代码实现)
      • [1.1.4 运行测试](#1.1.4 运行测试)
    • [1.2 用户登录](#1.2 用户登录)
      • [1.2.1 需求与准备](#1.2.1 需求与准备)
      • [1.2.2 前后端交互接口约定](#1.2.2 前后端交互接口约定)
      • [1.2.3 代码实现](#1.2.3 代码实现)
      • [1.2.4 运行测试](#1.2.4 运行测试)
    • [1.3 留言板](#1.3 留言板)
      • [1.3.1 需求与准备](#1.3.1 需求与准备)
      • [1.3.2 工具与依赖](#1.3.2 工具与依赖)
      • [1.3.3 前后端交互接口约定](#1.3.3 前后端交互接口约定)
      • [1.3.4 代码实现](#1.3.4 代码实现)
      • [1.3.5 运行测试](#1.3.5 运行测试)
    • [1.4 图书管理系统(基础版)](#1.4 图书管理系统(基础版))
      • [1.4.1 需求与准备](#1.4.1 需求与准备)
      • [1.4.2 前后端交互接口约定](#1.4.2 前后端交互接口约定)
      • [1.4.3 代码实现](#1.4.3 代码实现)
      • [1.4.4 运行测试](#1.4.4 运行测试)
  • 二、应用分层
    • [2.1 应用分层介绍](#2.1 应用分层介绍)
      • [2.1.1 核心概念](#2.1.1 核心概念)
      • [2.1.2 分层的必要性](#2.1.2 分层的必要性)
      • [2.1.3 MVC与三层架构的关系](#2.1.3 MVC与三层架构的关系)
    • [2.2 代码重构实践](#2.2 代码重构实践)
      • [2.2.1 项目结构调整](#2.2.1 项目结构调整)
      • [2.2.2 各层代码实现](#2.2.2 各层代码实现)
      • [2.2.3 分层架构的优势](#2.2.3 分层架构的优势)
  • 三、企业规范
    • [3.1 命名规范](#3.1 命名规范)
      • [3.1.1 类名规范](#3.1.1 类名规范)
      • [3.1.2 方法名、参数名、变量名规范](#3.1.2 方法名、参数名、变量名规范)
      • [3.1.3 包名规范](#3.1.3 包名规范)
      • [3.1.4 其他命名风格参考](#3.1.4 其他命名风格参考)
    • [3.2 编码规范](#3.2 编码规范)
      • [3.2.1 注解使用规范](#3.2.1 注解使用规范)
      • [3.2.2 代码格式规范](#3.2.2 代码格式规范)
      • [3.2.3 依赖与工具规范](#3.2.3 依赖与工具规范)
  • 四、总结

一、综合性练习

通过实际案例可深化对Spring MVC核心能力的理解,以下结合加法计算器、用户登录、留言板及图书管理系统四个案例,完整覆盖前后端交互流程、接口设计与数据处理逻辑。

1.1 加法计算器

1.1.1 需求与准备

需求为接收用户输入的两个整数,后端计算结果后返回给前端展示。准备工作需创建Spring Boot项目并引入Spring Web依赖,将前端页面calc.html放置在resources/static目录下,项目结构如下:

java 复制代码
com.example.demo
  DemoApplication
resources
  static
    calc.html
  templates
  application.properties

1.1.2 前后端交互接口约定

接口设计需明确请求路径、方式、参数与响应格式,具体如下:

接口要素 详情
请求路径 /calc/sum
请求方式 GET/POST
接口描述 计算两个整数相加
请求参数 num1(Integer,必传,参与计算的第一个数)、num2(Integer,必传,参与计算的第二个数)
响应数据 Content-Type为text/html,响应内容为HTML格式的计算结果(如"计算机计算结果: 8")
示例请求参数 num1=5&num2=3

1.1.3 代码实现

  • 后端代码 :创建CalcController类,通过@RestController标识为控制器并返回数据,@RequestMapping映射请求路径,直接接收参数并计算返回结果:
java 复制代码
@RestController
@RequestMapping("/calc")
public class CalcController {
    @RequestMapping("/sum")
    public String sum(Integer num1, Integer num2) {
        Integer sum = num1 + num2;
        return "<h1>计算机计算结果: " + sum + "</h1>";
    }
}
  • 前端代码:通过form表单指定请求路径与方式,提供输入框与提交按钮:
html 复制代码
<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>

1.1.4 运行测试

启动项目后,访问http://127.0.0.1:8080/calc.html,输入两个整数(如5和16),点击"点击相加"按钮,页面会跳转至/calc/sum并显示计算结果(如"计算机计算结果: 21")。

1.2 用户登录

1.2.1 需求与准备

需求为用户输入账号密码后,后端校验正确性:校验失败则前端弹窗提示,校验成功则跳转至首页并显示当前登录用户,且后续访问首页仍能保留登录状态。准备工作需将login.html(登录页)、index.html(首页)放置在resources/static目录下。

1.2.2 前后端交互接口约定

需设计两个核心接口:登录校验接口与登录用户查询接口:

  1. 登录校验接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /user/login |
    | 请求方式 | POST |
    | 接口描述 | 校验账号密码是否正确 |
    | 请求参数 | userName(String,必传,校验的账号)、password(String,必传,校验的密码) |
    | 响应数据 | Content-Type为text/html,响应内容为true(账号密码验证成功)或false(账号密码验证失败) |
  2. 查询登录用户接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /user/getLoginUser |
    | 请求方式 | GET |
    | 接口描述 | 查询当前登录的用户 |
    | 请求参数 | 无 |
    | 响应数据 | Content-Type为text/html,响应内容为当前登录用户名(未登录则返回空) |

1.2.3 代码实现

  • 后端代码 :创建LoginController类,使用HttpSession存储登录用户信息,StringUtils.hasLength()判断参数是否为空,固定账号密码(zhangsan/123456)进行校验:
java 复制代码
import jakarta.servlet.http.HttpSession;
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) {
        // 账号或密码为空时返回false
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
            return false;
        }
        // 校验账号密码,正确则存储用户信息到Session
        if ("zhangsan".equals(userName) && "123456".equals(password)) {
            session.setAttribute("userName", userName);
            return true;
        }
        return false;
    }

    @RequestMapping("/getLoginUser")
    public String getLoginUser(HttpSession session) {
        // 从Session中获取登录用户信息
        String userName = (String) session.getAttribute("userName");
        return StringUtils.hasLength(userName) ? userName : "";
    }
}
  • 前端代码 :登录页通过Ajax发送请求校验账号密码,成功则跳转首页;首页通过Ajax获取登录用户信息并展示:
    • 登录页(login.html):
html 复制代码
<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: {
            "userName": $("#userName").val(),
            "password": $("#password").val()
        },
        success: function (result) {
            if (result) {
                location.href = "/index.html"; // 登录成功跳转首页
            } else {
                alert("账号或密码有误."); // 登录失败弹窗提示
            }
        }
    });
}
</script>
  • 首页(index.html):
html 复制代码
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$.ajax({
    type: "get",
    url: "/user/getLoginUser",
    success: function (result) {
        $("#loginUser").text(result); // 展示当前登录用户
    }
});
</script>

1.2.4 运行测试

启动项目后,访问http://127.0.0.1:8080/login.html,输入正确账号密码(zhangsan/123456),登录成功后跳转至首页,首页显示"登录人:zhangsan";多次刷新首页仍能保留登录状态,重启服务器后登录状态丢失(因Session默认存储在内存)。

1.3 留言板

1.3.1 需求与准备

需求为用户输入留言人(谁)、接收人(对谁)、留言内容(说什么),提交后后端存储留言;页面加载时从后端获取所有历史留言并展示。准备工作需引入Lombok依赖简化实体类代码,将messagewall.html(留言板页面)放置在resources/static目录下。

1.3.2 工具与依赖

  • Lombok介绍 :Lombok是Java工具库,通过注解自动生成getter/settertoString等方法,减少冗余代码。需在pom.xml引入依赖:
xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
  • 核心注解@Data注解可自动生成gettersettertoStringequalshashCode及无参构造方法,等价于@Getter + @Setter + @ToString + @EqualsAndHashCode + @NoArgsConstructor

1.3.3 前后端交互接口约定

需设计两个接口:获取全部留言接口与发表新留言接口:

  1. 获取全部留言接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /message/getList |
    | 请求方式 | GET |
    | 接口描述 | 获取所有留言信息 |
    | 响应数据 | JSON格式的留言列表,每条留言包含from(留言人)、to(接收人)、message(留言内容) |
  2. 发表新留言接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /message/publish |
    | 请求方式 | POST |
    | 接口描述 | 提交新留言 |
    | 请求参数 | from(String,必传,留言人)、to(String,必传,接收人)、message(String,必传,留言内容) |
    | 响应数据 | JSON格式,ok: 1表示发表成功 |

1.3.4 代码实现

  • 模型层 :创建MessageInfo实体类,使用@Data注解简化代码:
java 复制代码
import lombok.Data;

@Data
public class MessageInfo {
    private String from;
    private String to;
    private String message;
}
  • 后端代码 :创建MessageController类,使用List<MessageInfo>存储留言(内存存储,重启服务器后数据丢失),提供接口处理留言获取与发表:
java 复制代码
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RequestMapping("/message")
@RestController
public class MessageController {
    // 存储留言信息(内存存储)
    private List<MessageInfo> messageInfos = new ArrayList<>();

    @RequestMapping("/getList")
    public List<MessageInfo> getList() {
        return messageInfos; // 返回所有留言
    }

    @RequestMapping("/publish")
    public boolean publish(MessageInfo messageInfo) {
        // 校验参数非空,非空则添加留言并返回true
        if (StringUtils.hasLength(messageInfo.getFrom())
                && StringUtils.hasLength(messageInfo.getTo())
                && StringUtils.hasLength(messageInfo.getMessage())) {
            messageInfos.add(messageInfo);
            return true;
        }
        return false; // 参数为空则返回false
    }
}
  • 前端代码 :页面加载时调用load()方法获取历史留言,点击提交按钮时调用submit()方法发表新留言并刷新页面:
html 复制代码
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
// 页面加载时获取留言
load();
function load() {
    $.ajax({
        type: "get",
        url: "/message/getList",
        success: function (result) {
            for (var message of result) {
                var divE = "<div>" + message.from + "对" + message.to + "说:" + message.message + "</div>";
                $(".container").append(divE); // 展示留言
            }
        }
    });
}

// 提交留言
function submit() {
    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 (result) {
            if (result) {
                // 发表成功,添加新留言到页面并清空输入框
                var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
                $(".container").append(divE);
                $('#from').val("");
                $('#to').val("");
                $('#say').val("");
            } else {
                alert("发表留言失败!");
            }
        }
    });
}
</script>

1.3.5 运行测试

访问http://127.0.0.1:8080/messagewall.html,输入留言信息(如"黑猫""白猫""喵"),点击提交后,页面下方会实时显示新留言;关闭页面后重新打开,历史留言仍能正常加载(数据存储在服务器内存中)。

1.4 图书管理系统(基础版)

1.4.1 需求与准备

需求为实现用户登录与图书列表展示功能:用户输入账号密码登录,登录成功后跳转至图书列表页,页面展示图书ID、书名、作者、数量、定价等信息,支持后续扩展添加、修改、删除图书功能。准备工作需创建新项目并引入Spring Web、Lombok依赖,将login.html(登录页)、book_list.html(图书列表页)放置在resources/static目录下。

1.4.2 前后端交互接口约定

核心接口包括登录校验接口与图书列表获取接口:

  1. 登录校验接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /user/login |
    | 请求方式 | POST |
    | 请求参数 | name(String,必传,用户名)、password(String,必传,密码) |
    | 响应数据 | true(登录成功)、false(登录失败) |
  2. 图书列表获取接口
    | 接口要素 | 详情 |
    |----------------|----------------------------------------------------------------------|
    | 请求路径 | /book/getList |
    | 请求方式 | POST |
    | 请求参数 | 无 |
    | 响应数据 | JSON格式的图书列表,每条图书包含id(图书ID)、bookName(书名)、author(作者)、count(数量)、price(定价)、publish(出版社)、status(状态)、statusCN(状态中文含义) |

1.4.3 代码实现

  • 模型层 :创建BookInfo实体类,使用@Data注解简化代码:
java 复制代码
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;

@Data
public class BookInfo {
    private Integer id; // 图书ID
    private String bookName; // 书名
    private String author; // 作者
    private Integer count; // 数量
    private BigDecimal price; // 定价
    private String publish; // 出版社
    private Integer status; // 状态(0-无效,1-可借阅,2-不可借阅)
    private String statusCN; // 状态中文含义
    private Date createTime; // 创建时间
    private Date updateTime; // 更新时间
}
  • 后端代码
    • 登录控制器(UserController):校验账号密码(固定为admin/admin),登录成功则存储用户名到Session:
java 复制代码
import jakarta.servlet.http.HttpSession;
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, 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;
    }
}
  • 图书控制器(BookController):通过mockData()方法模拟图书数据,处理图书状态中文转换并返回列表:
java 复制代码
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;

@RequestMapping("/book")
@RestController
public class BookController {
    @RequestMapping("/getList")
    public List<BookInfo> getList() {
        List<BookInfo> books = mockData(); // 获取模拟图书数据
        // 处理图书状态中文含义
        for (BookInfo book : books) {
            book.setStatusCN(book.getStatus() == 1 ? "可借阅" : "不可借阅");
        }
        return books;
    }

    // 模拟获取图书数据
    private 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)));
            book.setPublish("出版社" + i);
            book.setStatus(1); // 默认设置为可借阅状态
            books.add(book);
        }
        return books;
    }
}
  • 前端代码 :登录页通过Ajax校验账号密码并跳转,图书列表页通过Ajax获取数据并渲染表格:
    • 登录页(login.html):
html 复制代码
<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>
  • 图书列表页(book_list.html):
html 复制代码
<script src="js/jquery.min.js"></script>
<script>
// 获取图书列表并渲染表格
function getBookList() {
    $.ajax({
        type: "get",
        url: "/book/getList",
        success: function (result) {
            if (result != null) {
                var finalHtml = "";
                for (var book of result) {
                    finalHtml += '<tr>';
                    finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" 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); // 渲染表格数据
            }
        }
    });
}
// 页面加载时调用获取图书列表方法
getBookList();
</script>

1.4.4 运行测试

启动项目后,访问http://127.0.0.1:8080/login.html,输入账号密码admin/admin,登录成功后跳转至图书列表页,页面会展示5条模拟图书数据,包含图书ID、书名、作者等信息,且状态列显示"可借阅"。

二、应用分层

随着项目功能复杂度提升,代码堆砌会导致维护困难,应用分层通过按职责划分模块,实现高内聚、低耦合,是企业级开发的核心设计思想。

2.1 应用分层介绍

2.1.1 核心概念

应用分层是将应用程序按职责划分为多个层次,各层次专注于自身功能,通过协同工作提供完整服务的设计思想。常见的分层方式为"三层架构",结合Spring MVC框架,后端分层可细分为:

  • 表现层(Controller):接收前端请求,调用业务逻辑层处理,返回响应数据,是前后端交互的入口。
  • 业务逻辑层(Service):处理核心业务逻辑,如数据校验、状态转换、业务规则判断等,协调数据访问层完成数据操作。
  • 数据访问层(Dao):负责数据的增删改查操作,与数据库或其他数据源(如缓存、文件)交互,不包含业务逻辑。
  • 模型层(Model):定义实体类,封装数据结构,对应数据库表或业务对象,是各层之间数据传递的载体。

2.1.2 分层的必要性

  • 解耦需求:未分层时,代码中请求处理、业务逻辑、数据访问混合在一起,修改一处可能影响多处(如更换数据源需修改所有涉及数据操作的代码);分层后各层职责独立,降低层间依赖。
  • 维护效率:开发人员可专注于某一层开发(如前端工程师负责表现层交互,后端工程师负责业务逻辑与数据访问),问题定位更精准(如数据错误只需排查数据访问层)。
  • 扩展性:可轻松替换某一层的实现(如将Dao层的内存存储改为MySQL数据库,只需修改Dao层代码,Service与Controller层无需变动)。

2.1.3 MVC与三层架构的关系

MVC与三层架构均为软件工程中的架构模式,从不同角度实现解耦,二者并非替代关系,而是可共存互补:

  • MVC:关注"数据展示与处理分离",将系统分为Model(模型,包含数据与业务逻辑)、View(视图,用户交互界面)、Controller(控制器,请求分发),适用于前后端未完全分离的场景。
  • 三层架构:关注"数据处理维度的职责分离",将后端分为表现层(对应MVC的View+Controller)、业务逻辑层(对应MVC的Model核心业务逻辑)、数据访问层(对应MVC的Model数据操作),适用于前后端分离的后端开发。
  • 核心目的:二者均以"高内聚、低耦合"为设计原则,MVC解决前端展示与后端处理的耦合,三层架构解决后端内部业务逻辑与数据访问的耦合。

2.2 代码重构实践

以图书管理系统的图书列表功能为例,基于分层思想对代码进行重构,明确各层职责与依赖关系。

2.2.1 项目结构调整

重构后的项目按分层划分包路径,结构如下:

复制代码
java
com.example.demo
  controller       // 表现层(Controller)
    BookController.java
    UserController.java
  service          // 业务逻辑层(Service)
    BookService.java
  dao              // 数据访问层(Dao)
    BookDao.java
  model            // 模型层(Model)
    BookInfo.java
  DemoApplication.java // 项目启动类
resources
  static           // 静态资源(前端页面)
  templates
  application.properties

2.2.2 各层代码实现

  • 模型层(Model)BookInfo类,封装图书数据,使用Lombok的@Data注解:
java 复制代码
package com.example.demo.model;

import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;

@Data
public class BookInfo {
    private Integer id;
    private String bookName;
    private String author;
    private Integer count;
    private BigDecimal price;
    private String publish;
    private Integer status;
    private String statusCN;
    private Date createTime;
    private Date updateTime;
}
  • 数据访问层(Dao)BookDao类,负责模拟图书数据获取,仅包含数据操作,无业务逻辑:
java 复制代码
package com.example.demo.dao;

import com.example.demo.model.BookInfo;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class BookDao {
    // 模拟从数据源获取图书数据
    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)));
            book.setPublish("出版社" + i);
            book.setStatus(1);
            books.add(book);
        }
        return books;
    }
}
  • 业务逻辑层(Service)BookService类,调用Dao层获取数据,处理业务逻辑(图书状态中文转换):
java 复制代码
package com.example.demo.service;

import com.example.demo.dao.BookDao;
import com.example.demo.model.BookInfo;
import java.util.List;

public class BookService {
    // 调用Dao层获取数据并处理业务逻辑
    public List<BookInfo> getBookList() {
        BookDao bookDao = new BookDao();
        List<BookInfo> books = bookDao.mockData();
        // 业务逻辑:图书状态中文转换
        for (BookInfo book : books) {
            book.setStatusCN(book.getStatus() == 1 ? "可借阅" : "不可借阅");
        }
        return books;
    }
}
  • 表现层(Controller)BookController类,接收前端请求,调用Service层获取处理后的数据,返回响应:
java 复制代码
package com.example.demo.controller;

import com.example.demo.model.BookInfo;
import com.example.demo.service.BookService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RequestMapping("/book")
@RestController
public class BookController {
    @RequestMapping("/getList")
    public List<BookInfo> getList() {
        BookService bookService = new BookService();
        return bookService.getBookList(); // 调用Service层获取数据并返回
    }
}

2.2.3 分层架构的优势

  1. 职责清晰:各层仅关注自身职责,Controller不处理业务逻辑,Service不直接操作数据,Dao不包含业务规则,代码可读性提升。
  2. 降低耦合 :层间依赖通过接口或简单调用实现,如修改Dao层的数据源(从内存改为MySQL),只需修改BookDao类,Service与Controller层无需改动。
  3. 复用性强:业务逻辑封装在Service层,可被多个Controller调用(如图书列表功能可被普通用户、管理员等不同角色的Controller复用)。
  4. 便于测试:可对各层单独测试,如通过Mock工具测试Service层业务逻辑,无需依赖真实数据源或前端请求。

三、企业规范

企业规范是保证团队协作效率、代码一致性的重要准则,以下为Spring MVC开发中常见的企业级命名与编码规范(具体以所在企业要求为准)。

3.1 命名规范

3.1.1 类名规范

  • 使用大驼峰命名法 (所有单词首字母大写),如UserControllerBookServiceBookInfo
  • 特殊例外:DO(数据对象)、BO(业务对象)、DTO(数据传输对象)、VO(视图对象)、AO(应用对象)等,类名可按业务场景简化,如UserDOBookDTO

3.1.2 方法名、参数名、变量名规范

  • 统一使用小驼峰命名法 (第一个单词首字母小写,后续单词首字母大写),如getBookList()userNamebookPrice
  • 方法名需体现业务含义,如获取图书列表用getBookList(),而非method1();更新图书用updateBook(),而非modify()

3.1.3 包名规范

  • 统一使用小写字母 ,点分隔符之间为单个自然语义的英语单词,按分层或业务模块划分,如:
    • 表现层:com.example.demo.controller
    • 业务逻辑层:com.example.demo.service
    • 数据访问层:com.example.demo.dao
    • 模型层:com.example.demo.model
    • 工具类:com.example.demo.util

3.1.4 其他命名风格参考

  • 蛇形命名法 :用下划线(_)分隔单词,多用于数据库表名、配置文件参数,如user_idbook_name
  • 脊柱命名法 :用短横线(-)分隔单词,多用于URL路径、HTML标签属性,如/book-listclass="book-item"

3.2 编码规范

3.2.1 注解使用规范

  • @RestController@Controller区分:返回数据(如JSON、文本)用@RestController,返回静态页面用@Controller(需配合@ResponseBody返回数据)。
  • @RequestMapping路径规范:URL路径最前面建议加/(如/book/getList),多层路径按业务模块划分(如/user/login/book/update)。
  • 参数注解明确化:接收路径参数用@PathVariable,接收JSON参数用@RequestBody,参数重命名用@RequestParam,避免参数绑定歧义。

3.2.2 代码格式规范

  • 缩进:使用4个空格缩进,避免使用Tab键,保证不同编辑器下格式一致。
  • 空行:方法之间、代码块之间保留空行,如Controller中不同接口方法之间空一行,提高可读性。
  • 注释:核心业务逻辑、复杂算法需添加注释,注释内容简洁明了,说明"为什么做"而非"做了什么";类、方法可使用Javadoc注释,便于生成文档。

3.2.3 依赖与工具规范

  • 依赖版本统一:项目中Spring Boot、Spring MVC、Lombok等依赖版本需统一,避免版本冲突,如Spring Boot版本统一为3.2.0
  • 工具类使用:优先使用Spring提供的工具类(如StringUtils),避免重复造轮子;自定义工具类需放在util包下,且方法设计为静态方法(如DateUtils.formatDate())。

四、总结

Spring MVC作为Java后端核心Web框架,其学习核心围绕"注解使用""前后端交互""分层设计"三大维度展开:

  1. 注解体系 :掌握@RequestMapping(路由映射)、@RequestParam(参数重命名)、@RequestBody(接收JSON)、@PathVariable(路径参数)、@RestController(返回数据)等核心注解,是实现Spring MVC功能的基础。
  2. 交互流程 :请求处理需根据参数类型选择合适的接收方式(如单个参数直接接收、JSON参数用@RequestBody),响应处理需区分返回数据与静态页面(@RestController vs @Controller)。
  3. 分层设计:通过Controller(表现层)、Service(业务逻辑层)、Dao(数据访问层)的分层架构,实现代码解耦与复用,是企业级项目开发的标准模式。
  4. 工具与规范:Postman用于接口测试,Lombok简化实体类代码,企业规范保证团队协作效率,这些是提升开发效率的重要辅助。
相关推荐
Echoo华地13 小时前
GitLab社区版日志rotate失败的问题
1024程序员节
asfdsfgas14 小时前
华硕 Armoury Crate 安装卡 50% 不动:清理安装缓存文件的解决步骤
1024程序员节
安冬的码畜日常15 小时前
【JUnit实战3_10】第六章:关于测试的质量(上)
测试工具·junit·单元测试·测试覆盖率·1024程序员节·junit5
安冬的码畜日常15 小时前
【JUnit实战3_11】第六章:关于测试的质量(下)
junit·单元测试·tdd·1024程序员节·bdd·变异测试
zhangzhangkeji16 小时前
UE5 蓝图-11:本汽车蓝图的事件图表,汽车拆分事件,染色事件(绿蓝黄青)。
ue5·1024程序员节
傻童:CPU16 小时前
C语言需要掌握的基础知识点之树
c语言·1024程序员节
双翌视觉17 小时前
机器视觉的手机模组背光贴合应用
人工智能·机器学习·智能手机·1024程序员节
weixin_5168652617 小时前
STM32H750寄存器操作(硬件I2C)
stm32·1024程序员节
B站计算机毕业设计之家17 小时前
计算机视觉:pyqt5+yoloV5目标检测平台 python实战 torch 目标识别 大数据项目 目标跟踪(建议收藏)✅
深度学习·qt·opencv·yolo·目标检测·计算机视觉·1024程序员节