239
社区成员




这个作业属于哪个课程 | FZU_SE_teacherW_4 |
---|---|
这个作业要求在哪里 | 软件工程实践总结&个人技术博客 |
这个作业的目标 | 个人技术总结 |
其他参考文献 | 构建之法 |
Spring Boot 是基于 Spring 框架的快速开发框架,旨在简化 Spring 应用的开发过程。它的核心优势在于 简化开发、提高效率,同时提供了生产级的功能和灵活的扩展性,是现代 Java 应用开发的首选框架。它特别适合快速开发和部署微服务架构的应用。
@GetMapping("/records")
public ResponseEntity<List<DietRecord>> getDietRecords(
@RequestHeader(value = "Authorization", required = false) String token) {
try {
// 从token中获取用户ID
String userId = getUserIdFromToken(token);
if (userId == null) {
log.warn("Unauthorized access attempt to get diet records");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.info("Fetching diet records for user: {}", userId);
List<DietRecord> records = dietRecordRepository.findAllByUserId(userId);
return ResponseEntity.ok(records);
} catch (Exception e) {
log.error("Error fetching diet records", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PostMapping("/record")
public ResponseEntity<?> addDietRecord(
@RequestBody String jsonBody,
@RequestHeader(value = "Authorization", required = false) String token) {
try {
// 从token中获取用户ID
String userId = getUserIdFromToken(token);
if (userId == null) {
log.warn("Unauthorized access attempt to add diet record");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.info("Received diet record JSON for user {}: {}", userId, jsonBody);
DietRecord dietRecord = objectMapper.readValue(jsonBody, DietRecord.class);
dietRecord.setUserId(userId);
DietRecord savedRecord = dietRecordRepository.addDietRecord(dietRecord);
log.info("Successfully added diet record for user {}", userId);
return ResponseEntity.ok(savedRecord);
} catch (Exception e) {
log.error("Error adding diet record", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error: " + e.getMessage());
}
}
@GetMapping("/nutrition-needs")
public ResponseEntity<?> getNutritionNeeds(
@RequestHeader(value = "Authorization", required = false) String token) {
try {
// 从token中获取用户ID
String userId = getUserIdFromToken(token);
if (userId == null) {
log.warn("Unauthorized access attempt to get nutrition needs");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.info("Fetching nutrition needs for user: {}", userId);
UserProfile userProfile = userProfileRepository.getUserProfileByUserId(userId);
if (userProfile == null) {
log.warn("User profile not found for user: {}", userId);
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("User profile not found");
}
NutritionCalculator.NutritionNeeds needs = nutritionCalculator.calculateNutritionNeeds(
userProfile.getWeight(),
userProfile.getHeight(),
userProfile.getAge(),
userProfile.getGender(),
"中度活动", // 这里可以根据实际需求从请求参数获取或从用户配置中获取
"保持体重" // 同上
);
return ResponseEntity.ok(needs);
} catch (Exception e) {
log.error("Error calculating nutrition needs", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error: " + e.getMessage());
}
}
/**
* 从token中解析用户ID
* @param token Bearer token
* @return 用户ID,如果token无效则返回null
*/
private String getUserIdFromToken(String token) {
try {
if (token == null || !token.startsWith("Bearer ")) {
log.debug("Invalid token format");
return null;
}
// 移除"Bearer "前缀
token = token.substring(7);
Claims claims = JwtUtil.fromToken(token);
if (claims == null) {
log.warn("Failed to parse token claims");
return null;
}
String userId = claims.get("user_id", String.class);
log.debug("Successfully extracted user_id from token: {}", userId);
return userId;
} catch (Exception e) {
log.error("Error parsing token", e);
return null;
}
}
定义了实际页面中按下不同按钮对应调用的方法
public Integer getDietId() {
return dietId;
}
public void setDietId(Integer dietId) {
this.dietId = dietId;
}
public String getUserId() {
return userId;
}
//后续相似代码省略
提供了后续代码逻辑中需要用到的字段的获取方法
@Repository
public class DietRecordRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public DietRecord addDietRecord(DietRecord record) {
String sql = "INSERT INTO diet_record (user_id, food_name, calories, meal_time, meal_type) VALUES (?, ?, ?, ?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, record.getUserId());
ps.setString(2, record.getFoodName());
ps.setBigDecimal(3, record.getCalories());
ps.setTimestamp(4, Timestamp.from(record.getMealTime().toInstant()));
ps.setString(5, record.getMealType());
return ps;
}, keyHolder);
int generatedId = keyHolder.getKey().intValue();
record.setDietId(generatedId);
return record;
}
public List<DietRecord> findAllByUserId(String userId) {
String sql = "SELECT * FROM diet_record WHERE user_id = ? ORDER BY meal_time DESC";
return jdbcTemplate.query(sql, new Object[]{userId}, (rs, rowNum) -> mapRowToDietRecord(rs));
}
private DietRecord mapRowToDietRecord(ResultSet rs) throws SQLException {
DietRecord record = new DietRecord();
record.setDietId(rs.getInt("diet_id"));
record.setUserId(rs.getString("user_id"));
record.setFoodName(rs.getString("food_name"));
record.setCalories(rs.getBigDecimal("calories"));
record.setMealTime(rs.getTimestamp("meal_time").toInstant().atOffset(ZoneOffset.UTC));
record.setMealType(rs.getString("meal_type"));
record.setCreatedAt(rs.getTimestamp("created_at").toInstant().atOffset(ZoneOffset.UTC));
record.setUpdatedAt(rs.getTimestamp("updated_at").toInstant().atOffset(ZoneOffset.UTC));
return record;
}
}
提供了将相关数据插入数据库对应表的操作
package com.example.health;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@Component
public class JwtUtil {
private static final String SECRET_KEY = "d8c986df-8512-42b5-906f-eeea9b3acf86";
private static final SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));
public static Claims fromToken(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
return null;
}
}
处理 JWT以及token
@Component
public class NutritionCalculator {
public static class NutritionNeeds {
private double calories;
private double protein;
private double carbs;
private double fat;
// Getter和Setter方法
public double getCalories() { return calories; }
public void setCalories(double calories) { this.calories = calories; }
public double getProtein() { return protein; }
public void setProtein(double protein) { this.protein = protein; }
public double getCarbs() { return carbs; }
public void setCarbs(double carbs) { this.carbs = carbs; }
public double getFat() { return fat; }
public void setFat(double fat) { this.fat = fat; }
}
public NutritionNeeds calculateNutritionNeeds(double weight, double height, int age, String gender, String activityLevel, String goal) {
double bmr = calculateBMR(gender, weight, height, age);
double tdee = calculateTDEE(bmr, activityLevel);
return calculateDailyNutritionNeeds(tdee, goal, weight);
}
private double calculateBMR(String gender, double weight, double height, int age) {
if (gender.equalsIgnoreCase("男")) {
return 88.362 + (13.397 * weight) + (4.799 * height) - (5.677 * age);
} else {
return 447.593 + (9.247 * weight) + (3.098 * height) - (4.330 * age);
}
}
private double calculateTDEE(double bmr, String activityLevel) {
double activityMultiplier = getActivityMultiplier(activityLevel);
return bmr * activityMultiplier;
}
private NutritionNeeds calculateDailyNutritionNeeds(double tdee, String goal, double weight) {
NutritionNeeds needs = new NutritionNeeds();
double adjustedCalories = adjustCaloriesForGoal(tdee, goal);
needs.setCalories(adjustedCalories);
needs.setProtein(weight * 2.2); // 每公斤体重2.2克蛋白质
needs.setCarbs(adjustedCalories * 0.45 / 4); // 45%的卡路里来自碳水,1克碳水4卡路里
needs.setFat(adjustedCalories * 0.25 / 9); // 25%的卡路里来自脂肪,1克脂肪9卡路里
return needs;
}
private double getActivityMultiplier(String activityLevel) {
switch (activityLevel.toLowerCase()) {
case "久坐":
return 1.2;
case "轻度活动":
return 1.375;
case "中度活动":
return 1.55;
case "高度活动":
return 1.725;
case "非常活跃":
return 1.9;
default:
return 1.2;
}
}
private double adjustCaloriesForGoal(double tdee, String goal) {
switch (goal.toLowerCase()) {
case "减重":
return tdee - 500; // 每天减少500卡路里
case "增重":
return tdee + 500; // 每天增加500卡路里
case "保持体重":
default:
return tdee;
}
}
包含bmr、每日营养需求、每日能量消耗的计算逻辑
public class UserProfile {
private String userId;
private String name;
private String gender;
private LocalDate birthday;
private double height;
private double weight;
public UserProfile(String userId, String name, String gender, LocalDate birthday, double height, double weight) {
this.userId = userId;
this.name = name;
this.gender = gender;
this.birthday = birthday;
this.height = height;
this.weight = weight;
}
public String getUserId() { return userId; }
public String getName() { return name; }
public String getGender() { return gender; }
public LocalDate getBirthday() { return birthday; }
public double getHeight() { return height; }
public double getWeight() { return weight; }
public int getAge() {
return Period.between(birthday, LocalDate.now()).getYears();
}
提供了后续代码逻辑中需要用到的用户数据相关的获取方法
@Repository
public class UserProfileRepository {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserProfileRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public UserProfile getUserProfileByUserId(String userId) {
String sql = "SELECT * FROM user_profile WHERE user_id = ?";
try {
return jdbcTemplate.queryForObject(sql, new Object[]{userId}, (rs, rowNum) -> {
LocalDate birthday = null;
Date birthdayDate = rs.getDate("birthday");
if (birthdayDate != null) {
birthday = birthdayDate.toLocalDate();
}
return new UserProfile(
rs.getString("user_id"),
rs.getString("name"),
rs.getString("gender"),
birthday,
rs.getDouble("height"),
rs.getDouble("weight")
);
});
} catch (EmptyResultDataAccessException e) {
return null;
} catch (Exception e) {
// 捕获其他异常
e.printStackTrace(); // 或者使用日志记录错误
return null;
}
}
从数据库中获取相关用户的基础数据并保存到一个对象中
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(
"http://123.60.177.200:8083", // 登录系统域名
"http://localhost:8084" // 本地开发环境
)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
用于配置跨域访问规则
报错:Syntax Error:TypeError: ICannot read properties of undefined (reading:'parseComponent')
解决:命令行输入npm add vue-template-compiler
报错:无法识别某某字段
解决:pom.xml中依赖未加载或依赖版本不正确,首先解决网络问题,更改maven为国内镜像,找到maven的settings.xml文件,找到 标签,添加或替换如阿里云镜像:
随后从新加载依赖,一般就可以解决这个问题,若还未解决,可以手动从官网下载对应依赖并添加
用于快速构建基于 Spring 的独立、生产级应用。提供自动化配置,减少开发工作量。内置嵌入式服务器(如 Tomcat),无需额外配置。生态体系完善,支持多种扩展。
提供 RESTful API 的开发框架。简化了 HTTP 请求的处理和响应。提供注解支持(如 @RestController
, @RequestMapping
),代码更简洁。
用于与数据库交互,执行 SQL 查询和更新。提供模板化的数据库操作(如 JdbcTemplate
),简化了数据库访问代码。自动管理资源(如连接关闭),减少内存泄漏风险。
用于用户身份验证,解析和生成用户令牌。无需服务器存储会话信息,减少存储开销。提高安全性,支持跨平台认证。
用于记录系统运行时的日志信息。便于调试和问题排查。支持日志级别控制(如 INFO、WARN、ERROR)。
用于 JSON 数据的序列化和反序列化。高效处理 JSON 数据。支持复杂对象的映射。
允许跨域请求。支持前后端分离的开发模式。提供灵活的跨域策略配置。
性能优异,适合中小型项目。社区支持丰富,生态完善。
构建动态的、响应式的单页面应用 (SPA)。数据绑定简单,组件化开发高效。支持 MVVM 模型,视图和数据逻辑分离。
处理 HTTP 请求,用于与后端 API 通信。提供更简洁的 API 调用方式。支持请求拦截器和响应拦截器。
构建页面结构和样式。使用现代化的 CSS(如 Flexbox 和 Grid)创建响应式布局。加载 Google 字体和自定义样式,提升用户体验。
在后端将 JSON 转换为 Java 对象,或将 Java 对象转换为 JSON。简化数据格式转换。减少手动解析 JSON 的复杂性。
通过 index.html
提供用户界面。使用 Vue.js 和 Axios 实现动态交互。提供直观的用户体验。