基于Spring MVC的码头管理系统2D平面图实现技术咨询
解决方案
1. 定义码头数据模型
先创建一个封装码头属性的实体类,用于在Controller和视图间传递数据:
public class Dock { private int x; // 左上角x坐标(数学坐标系,从左下原点开始) private int y; // 左上角y坐标 private int width; // 码头宽度 private int height; // 码头高度 private String name; // 码头名称(用于标注) // 构造函数、getter、setter按需实现 }
2. Controller层处理数据传递
Controller只负责准备数据并传递到JSP,不处理任何绘图逻辑,核心代码如下:
@Controller @RequestMapping("/dock") public class DockController { @GetMapping("/plan") public String showDockPlan(Model model) { // 替换为从数据库/服务层获取的真实数据 List<Dock> docks = new ArrayList<>(); docks.add(new Dock(50, 100, 150, 80, "码头A")); docks.add(new Dock(250, 150, 120, 100, "码头B")); docks.add(new Dock(100, 280, 200, 70, "码头C")); // 设置画布和坐标轴参数(根据实际场景调整) model.addAttribute("canvasWidth", 500); model.addAttribute("canvasHeight", 400); model.addAttribute("axisMaxX", 500); model.addAttribute("axisMaxY", 400); model.addAttribute("docks", docks); return "dock-plan"; // 返回对应的JSP视图名称 } }
3. JSP视图实现2D平面图
提供两种实用方案,根据需求选择:
方案A:HTML+CSS绘制(适合简单静态场景)
利用绝对定位的div模拟码头矩形,配合CSS实现坐标轴:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>码头平面图</title> <style> .canvas-container { position: relative; width: ${canvasWidth}px; height: ${canvasHeight}px; border: 2px solid #333; margin: 20px; } .axis-x { position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background: #000; } .axis-y { position: absolute; top: 0; left: 0; width: 2px; height: 100%; background: #000; } .dock-rect { position: absolute; border: 2px solid #2196F3; background: rgba(33, 150, 243, 0.2); display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 14px; } .axis-label { position: absolute; font-size: 12px; color: #666; } </style> </head> <body> <h2>码头2D平面图</h2> <div class="canvas-container"> <!-- 坐标轴 --> <div class="axis-x"></div> <div class="axis-y"></div> <!-- 渲染码头矩形 --> <c:forEach items="${docks}" var="dock"> <div class="dock-rect" style="left: ${dock.x}px; bottom: ${dock.y}px; width: ${dock.width}px; height: ${dock.height}px;"> ${dock.name} </div> </c:forEach> <!-- 坐标轴刻度标签 --> <c:forEach var="i" begin="0" end="${axisMaxX}" step="100"> <div class="axis-label" style="left: ${i}px; bottom: -20px;">${i}</div> </c:forEach> <c:forEach var="i" begin="0" end="${axisMaxY}" step="100"> <div class="axis-label" style="left: -20px; bottom: ${i}px;">${i}</div> </c:forEach> </div> </body> </html>
方案B:Canvas绘制(适合需要交互的场景)
如果需要缩放、拖拽等交互功能,用Canvas更灵活:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>码头平面图</title> <style> canvas { border: 2px solid #333; margin: 20px; } </style> </head> <body> <h2>码头2D平面图</h2> <canvas id="dockCanvas" width="${canvasWidth}" height="${canvasHeight}"></canvas> <script> const canvas = document.getElementById('dockCanvas'); const ctx = canvas.getContext('2d'); const axisMaxX = ${axisMaxX}; const axisMaxY = ${axisMaxY}; const docks = [ <c:forEach items="${docks}" var="dock" varStatus="status"> {x: ${dock.x}, y: ${dock.y}, width: ${dock.width}, height: ${dock.height}, name: "${dock.name}" }<c:if test="${!status.last}">,</c:if> </c:forEach> ]; // 绘制坐标轴 ctx.beginPath(); ctx.moveTo(0, canvas.height); ctx.lineTo(canvas.width, canvas.height); // X轴 ctx.moveTo(0, 0); ctx.lineTo(0, canvas.height); // Y轴 ctx.strokeStyle = '#000'; ctx.lineWidth = 2; ctx.stroke(); // 绘制坐标轴刻度和标签 ctx.font = '12px Arial'; ctx.fillStyle = '#666'; // X轴刻度 for (let i = 0; i <= axisMaxX; i += 100) { ctx.moveTo(i, canvas.height); ctx.lineTo(i, canvas.height - 5); ctx.stroke(); ctx.fillText(i, i - 15, canvas.height + 20); } // Y轴刻度(转换Canvas坐标系) for (let i = 0; i <= axisMaxY; i += 100) { const yPos = canvas.height - i; ctx.moveTo(0, yPos); ctx.lineTo(5, yPos); ctx.stroke(); ctx.fillText(i, -25, yPos + 5); } // 绘制码头矩形 docks.forEach(dock => { // 转换Canvas Y轴坐标(Canvas原点在左上,需转成数学坐标系的左下原点) const yPos = canvas.height - dock.y - dock.height; ctx.beginPath(); ctx.rect(dock.x, yPos, dock.width, dock.height); ctx.strokeStyle = '#2196F3'; ctx.lineWidth = 2; ctx.stroke(); ctx.fillStyle = 'rgba(33, 150, 243, 0.2)'; ctx.fill(); // 绘制码头名称 ctx.fillStyle = '#333'; ctx.font = 'bold 14px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(dock.name, dock.x + dock.width/2, yPos + dock.height/2); }); </script> </body> </html>
关键注意事项
- Controller职责边界:只负责数据准备,绘图逻辑完全交给前端,避免后端做可视化工作。
- 坐标转换:HTML/CSS和Canvas的坐标系与常规数学坐标系不同,需要通过
bottom属性或坐标计算对齐需求。 - 数据替换:示例中的模拟数据,实际项目中替换为从数据库或业务服务获取的真实码头数据即可。
内容的提问来源于stack exchange,提问作者Réda
相关产品推荐
相关产品推荐

