【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简化实体类代码,企业规范保证团队协作效率,这些是提升开发效率的重要辅助。
相关推荐
学传打活4 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续3)
微信公众平台·1024程序员节·汉字·昆仑正义文化
学传打活9 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16817 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心19 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552725 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055271 个月前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝1 个月前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055271 个月前
Java图像处理实战指南
人工智能·1024程序员节
u0103055271 个月前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055271 个月前
Java实用类应用精讲
人工智能·1024程序员节