作为一名混迹Java圈五年的老手,我最近完成了一个基于SpringBoot和Vue.js的健康管理系统项目。这个系统解决了现代人健康数据管理分散、缺乏可视化分析的痛点。通过前后端分离架构,实现了体重、血压、血糖等健康指标的数字化管理,并提供趋势分析和预警功能。
系统采用主流技术栈组合:后端使用SpringBoot 2.7 + MyBatis Plus构建RESTful API,前端采用Vue 3 + Element Plus实现响应式界面,数据库选用MySQL 8.0。这种技术组合既保证了开发效率,又能支撑高并发场景。下面我将从架构设计到具体实现,分享这个项目的完整开发经验。
后端选择SpringBoot主要基于以下考虑:
前端选择Vue.js的核心优势:
系统采用经典的三层架构:
code复制表示层(Vue)
↓
业务逻辑层(SpringBoot)
↓
数据访问层(MyBatis Plus)
前后端通过JSON格式数据进行通信,接口设计遵循RESTful规范。特别设计了JWT鉴权机制,保障用户健康数据安全。
java复制// JWT工具类核心代码
public class JwtUtil {
private static final String SECRET = "health@2023";
public static String generateToken(User user) {
return Jwts.builder()
.setSubject(user.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}
java复制@RestController
@RequestMapping("/api/health")
public class HealthDataController {
@Autowired
private HealthDataService healthDataService;
@PostMapping
public Result addData(@RequestBody HealthData healthData) {
return healthDataService.save(healthData)
? Result.success() : Result.error("添加失败");
}
@GetMapping("/trend")
public Result getTrend(@RequestParam String type,
@RequestParam String period) {
return Result.success(
healthDataService.getTrendData(type, period)
);
}
}
vue复制<template>
<div class="chart-container">
<line-chart
:chart-data="chartData"
:options="chartOptions"/>
</div>
</template>
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: ['chartData'],
data() {
return {
chartOptions: {
responsive: true,
maintainAspectRatio: false
}
}
},
mounted() {
this.renderChart(this.chartData, this.chartOptions)
}
}
</script>
javascript复制export default {
data() {
return {
rules: {
weight: [
{ required: true, message: '请输入体重', trigger: 'blur' },
{ type: 'number', min: 20, max: 200,
message: '体重应在20-200kg之间', trigger: 'blur' }
],
bloodPressure: [
{ validator: (rule, value, callback) => {
if (!/^\d+\/\d+$/.test(value)) {
callback(new Error('格式应为120/80'))
} else {
callback()
}
}, trigger: 'blur'
}
]
}
}
}
}
sql复制CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`phone` varchar(20) DEFAULT NULL,
`gender` tinyint DEFAULT '0',
`birthday` date DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
sql复制CREATE TABLE `health_data` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`type` varchar(20) NOT NULL COMMENT '数据类型',
`value` varchar(50) NOT NULL,
`record_time` datetime NOT NULL,
`notes` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_type` (`user_id`,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
采用Docker容器化部署:
dockerfile复制# 后端Dockerfile
FROM openjdk:11-jre
COPY target/health-system.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 前端Dockerfile
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
Nginx配置示例:
nginx复制server {
listen 80;
server_name health.example.com;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
}
yaml复制mybatis-plus:
configuration:
cache-enabled: true
java复制@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "health-system");
}
javascript复制const routes = [
{
path: '/report',
component: () => import('./views/Report.vue')
}
]
开发阶段可在SpringBoot中添加配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
生产环境建议通过Nginx反向代理解决跨域,更安全高效。
前后端日期格式统一方案:
java复制// 后端全局配置
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> {
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
builder.serializers(new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
};
}
前端使用day.js处理日期:
javascript复制import dayjs from 'dayjs'
const formatted = dayjs('2023-07-15').format('YYYY年MM月DD日')
对于大量历史数据展示,采用以下策略:
java复制public List<HealthData> getSampledData(Long userId, String type, int days) {
// 按天数采样,每天取最早、最晚、最大值、最小值四个点
return baseMapper.selectSampledData(userId, type, days);
}
实现健康报告生成的示例代码:
java复制public void generateReport(Long userId, HttpServletResponse response) {
User user = userService.getById(userId);
List<HealthData> data = healthDataService.listByUser(userId);
XWPFTemplate template = XWPFTemplate.compile("template.docx")
.render(new Context(
BeansMap.create()
.put("user", user)
.put("data", data)
));
response.setContentType("application/octet-stream");
template.writeAndClose(response.getOutputStream());
}
这个项目让我深刻体会到SpringBoot和Vue.js组合的开发效率优势。特别是在处理健康数据这类敏感信息时,完善的权限控制和数据加密必不可少。建议在类似项目中,尽早考虑数据隐私保护方案,比如对敏感字段进行加密存储。