1. Spring MVC实战:从加法计算器到留言板的Web开发全流程
作为JavaEE开发的核心框架,Spring MVC在现代化Web开发中扮演着交通枢纽的角色。今天我将通过三个典型场景——加法计算器、用户登录系统和留言板,带大家深入掌握Spring MVC的核心开发技巧。这些案例虽然基础,但涵盖了前后端分离开发中最关键的接口设计、会话管理和数据交互模式。
2. 加法计算器:前后端交互的标准化实践
2.1 项目初始化与前端准备
首先创建一个标准的SpringBoot项目,引入Spring Web依赖。前端页面我们采用最简单的HTML表单:
html复制<!DOCTYPE html>
<html>
<head>
<title>加法计算器</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>
这个表单有几个关键设计点:
- action属性指向
calc/sum路径,与后端控制器映射一致 - method使用POST方式提交(虽然GET也可以,但涉及数据修改建议用POST)
- input的name属性
num1/num2将作为后端接收的参数名
2.2 接口设计规范详解
前后端分离开发中,接口文档是团队协作的基石。对于加法计算器,我们定义的接口规范如下:
| 要素 | 说明 |
|---|---|
| 请求路径 | /calc/sum |
| 请求方法 | POST |
| 参数 | num1(整数), num2(整数) |
| 响应类型 | text/html |
| 成功响应示例 | "计算结果:30" |
| 错误处理 | 参数为空时返回"输入数据不合法" |
实际项目中建议使用Swagger或YAPI等工具维护接口文档,这里展示的是最基础的文档形式
2.3 控制器实现与参数处理
后端控制器需要处理表单提交并返回计算结果:
java复制@RestController
@RequestMapping("/calc")
public class CalcController {
@PostMapping("/sum")
public String calculateSum(
@RequestParam(required = false) Integer num1,
@RequestParam(required = false) Integer num2) {
if (num1 == null || num2 == null) {
return "输入的数据不合法";
}
return "计算结果:" + (num1 + num2);
}
}
关键实现细节:
@RestController组合了@Controller和@ResponseBody,适合RESTful接口@RequestParam(required = false)表示参数非必须,但业务上需要判空- 直接返回字符串会被自动设置为text/html内容类型
- 数值计算前建议增加范围校验(如防止整数溢出)
2.4 常见问题排查
- 404错误:检查
@RequestMapping路径是否匹配,注意应用上下文路径 - 参数获取为null:确认表单字段名与
@RequestParam名称一致 - 中文乱码:确保配置了Spring的字符编码过滤器
- 跨域问题:开发时可添加
@CrossOrigin注解临时解决
3. 用户登录系统:会话管理实战
3.1 登录流程设计
用户登录是Web开发的经典场景,涉及以下核心流程:
- 前端提交用户名密码
- 后端验证凭证
- 创建会话标识
- 后续请求携带会话标识
3.2 接口规范设计
我们定义两个关键接口:
登录接口
code复制POST /user/login
参数:userName, password
响应:true/false
获取当前用户接口
code复制GET /user/getLoginUser
响应:当前登录用户名或空字符串
3.3 会话管理实现
java复制@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/login")
public Boolean login(String userName, String password,
HttpSession session) {
if (!StringUtils.hasText(userName) || !StringUtils.hasText(password)) {
return false;
}
// 实际项目应查询数据库
if ("admin".equals(userName) && "123456".equals(password)) {
session.setAttribute("loginUser", userName);
return true;
}
return false;
}
@GetMapping("/getLoginUser")
public String getLoginUser(HttpServletRequest request) {
HttpSession session = request.getSession(false);
return session != null ? (String)session.getAttribute("loginUser") : "";
}
}
安全注意事项:
- 密码永远不要明文存储
- 会话过期时间应合理设置
- 重要操作需要二次认证
- 防范CSRF攻击
3.4 前端集成示例
登录页面关键代码:
javascript复制function login() {
$.post("/user/login", {
userName: $("#userName").val(),
password: $("#password").val()
}, function(result) {
if (result) {
location.href = "/home.html";
} else {
alert("登录失败");
}
});
}
首页获取当前用户:
javascript复制$.get("/user/getLoginUser", function(username) {
if (username) {
$("#loginUser").text(username);
}
});
4. 留言板系统:JSON交互与Lombok应用
4.1 功能需求分析
留言板需要支持:
- 提交新留言(from, to, message)
- 查看所有留言列表
- 数据持久化(本例使用内存存储)
4.2 RESTful接口设计
采用JSON作为数据交换格式:
获取留言列表
code复制GET /message/list
响应:[{"from":"A","to":"B","message":"hello"},...]
提交留言
code复制POST /message/publish
请求体:{"from":"A","to":"B","message":"hello"}
响应:{"success":true}
4.3 Lombok简化开发
引入Lombok依赖:
xml复制<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
留言实体类简化:
java复制@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message {
private String from;
private String to;
private String content;
}
@Data注解自动生成getter/setter/toString等方法,极大减少样板代码。
4.4 控制器实现
java复制@RestController
@RequestMapping("/message")
public class MessageController {
private List<Message> messages = new ArrayList<>();
@GetMapping("/list")
public List<Message> getMessages() {
return messages;
}
@PostMapping("/publish")
public ResponseEntity<Map<String, Boolean>> publishMessage(
@RequestBody Message message) {
if (!StringUtils.hasText(message.getFrom()) ||
!StringUtils.hasText(message.getTo()) ||
!StringUtils.hasText(message.getContent())) {
return ResponseEntity.badRequest().build();
}
messages.add(message);
return ResponseEntity.ok(Collections.singletonMap("success", true));
}
}
4.5 前端交互实现
提交留言的JavaScript代码:
javascript复制function submitMessage() {
const message = {
from: $("#from").val(),
to: $("#to").val(),
content: $("#content").val()
};
$.ajax({
url: "/message/publish",
type: "POST",
contentType: "application/json",
data: JSON.stringify(message),
success: function() {
loadMessages(); // 刷新留言列表
}
});
}
加载留言列表:
javascript复制function loadMessages() {
$.get("/message/list", function(messages) {
const container = $(".message-container");
container.empty();
messages.forEach(msg => {
container.append(
`<div>${msg.from}对${msg.to}说:${msg.content}</div>`
);
});
});
}
5. 开发经验与最佳实践
在实际项目中,还有一些值得注意的经验:
- 接口版本控制:在路径中加入
/v1/前缀,为后续接口变更留余地 - 统一响应格式:建议封装统一的响应对象,如:
java复制public class Result<T> { private int code; private String message; private T data; // 省略构造方法和getter/setter } - 参数校验:使用
@Valid和Hibernate Validator进行声明式校验 - 异常处理:通过
@ControllerAdvice实现全局异常处理 - 跨域处理:正式环境应通过网关或Nginx配置,而非
@CrossOrigin
对于会话管理,在分布式系统中需要考虑:
- 采用无状态JWT替代Session
- 使用Redis等集中式存储会话数据
- 实现单点登录(SSO)方案
在前后端协作方面:
- 使用Mock.js等工具在前端开发阶段模拟接口
- 定期同步接口文档变更
- 约定枚举值的表示方式
性能优化建议:
- 对频繁访问的接口添加缓存
- 采用分页加载代替全量数据
- 压缩JSON数据大小
- 启用HTTP/2协议
6. 项目扩展方向
基于这三个基础案例,可以进一步扩展为完整的应用:
-
计算器增强:
- 支持更多运算类型
- 增加计算历史记录
- 实现科学计算功能
-
用户系统增强:
- 添加注册功能
- 实现权限控制
- 增加个人资料管理
-
留言板增强:
- 添加分页查询
- 支持富文本留言
- 增加点赞/回复功能
技术栈扩展建议:
- 集成MyBatis或JPA访问数据库
- 添加Spring Security进行安全控制
- 使用WebSocket实现实时通知
- 引入Thymeleaf等服务端模板引擎
对于企业级开发,还需要考虑:
- 接口幂等性设计
- 防重放攻击机制
- 敏感数据加密
- 操作日志记录
通过这三个案例的实践,我们完整走过了从接口设计到前后端联调的Web开发全流程。Spring MVC的强大之处在于它提供了灵活而规范的Web开发模式,让开发者能够专注于业务逻辑的实现。