双11狂欢大促

盲盒赢 定制羽绒服

开启惊喜盲盒,抽取你的专属好礼

— 惊喜奖品抢先看 —

个人技术博客——spring boot

cw1275204060 cw1275204060 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
这个作业属于哪个课程FZU_SE_teacherW_4
这个作业要求在哪里软件工程实践总结&个人技术博客
这个作业的目标个人技术总结
其他参考文献构建之法

目录

  • 1.技术概括
  • 2.技术详述
  • 2.1 控制层(DietController)
  • 2.2 DietRecord
  • 2.3 DietRecordRepository
  • 2.4 JWTUtil
  • 2.5 NutritionCalculator
  • 2.6 UserProfile
  • 2.7 UserProfileRepository
  • 2.8 WebConfig
  • 3.问题与解决
  • 3.1 测试Vue项目时运行报错
  • 3.2 springboot项目依赖导入问题
  • 4.总结
  • 4.1后端技术栈
  • 4.1.1. Spring Boot
  • 4.1.2. Spring MVC
  • 4.1.3. Spring JDBC
  • 4.1.4. JWT(JSON Web Token)
  • 4.1.5. 日志框架 (SLF4J + Logback)
  • 4.1.6. Jackson
  • 4.1.7. Spring 的 CORS 配置
  • 4.2数据库
  • 4.2.1. MySQL
  • 4.3前端技术栈
  • 1. Vue.js
  • 2. Axios
  • 3. HTML + CSS
  • 4.4其他
  • 4.4.1. ObjectMapper
  • 4.4.2. 静态资源
  • 5.参考文献

1.技术概括

Spring Boot 是基于 Spring 框架的快速开发框架,旨在简化 Spring 应用的开发过程。它的核心优势在于 简化开发、提高效率,同时提供了生产级的功能和灵活的扩展性,是现代 Java 应用开发的首选框架。它特别适合快速开发和部署微服务架构的应用。

2.技术详述

2.1 控制层(DietController)

@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;
    }
}

定义了实际页面中按下不同按钮对应调用的方法

2.2 DietRecord

 public Integer getDietId() {
    return dietId;
}

public void setDietId(Integer dietId) {
    this.dietId = dietId;
}

public String getUserId() {
    return userId;
}
//后续相似代码省略

提供了后续代码逻辑中需要用到的字段的获取方法

2.3 DietRecordRepository

@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;
}

}
提供了将相关数据插入数据库对应表的操作

2.4 JWTUtil

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

2.5 NutritionCalculator

@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、每日营养需求、每日能量消耗的计算逻辑

2.6 UserProfile

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();
}

提供了后续代码逻辑中需要用到的用户数据相关的获取方法

2.7 UserProfileRepository

@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;
    }
}

从数据库中获取相关用户的基础数据并保存到一个对象中

2.8 WebConfig

@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);
}
}

用于配置跨域访问规则

3.问题与解决

3.1 测试Vue项目时运行报错

报错:Syntax Error:TypeError: ICannot read properties of undefined (reading:'parseComponent')
解决:命令行输入npm add vue-template-compiler

3.2 springboot项目依赖导入问题

报错:无法识别某某字段
解决:pom.xml中依赖未加载或依赖版本不正确,首先解决网络问题,更改maven为国内镜像,找到maven的settings.xml文件,找到 标签,添加或替换如阿里云镜像:

img

随后从新加载依赖,一般就可以解决这个问题,若还未解决,可以手动从官网下载对应依赖并添加

4.总结

4.1后端技术栈

4.1.1. Spring Boot

用于快速构建基于 Spring 的独立、生产级应用。提供自动化配置,减少开发工作量。内置嵌入式服务器(如 Tomcat),无需额外配置。生态体系完善,支持多种扩展。

4.1.2. Spring MVC

提供 RESTful API 的开发框架。简化了 HTTP 请求的处理和响应。提供注解支持(如 @RestController, @RequestMapping),代码更简洁。

4.1.3. Spring JDBC

用于与数据库交互,执行 SQL 查询和更新。提供模板化的数据库操作(如 JdbcTemplate),简化了数据库访问代码。自动管理资源(如连接关闭),减少内存泄漏风险。

4.1.4. JWT(JSON Web Token)

用于用户身份验证,解析和生成用户令牌。无需服务器存储会话信息,减少存储开销。提高安全性,支持跨平台认证。

4.1.5. 日志框架 (SLF4J + Logback)

用于记录系统运行时的日志信息。便于调试和问题排查。支持日志级别控制(如 INFO、WARN、ERROR)。

4.1.6. Jackson

用于 JSON 数据的序列化和反序列化。高效处理 JSON 数据。支持复杂对象的映射。

4.1.7. Spring 的 CORS 配置

允许跨域请求。支持前后端分离的开发模式。提供灵活的跨域策略配置。

4.2数据库

4.2.1. MySQL

性能优异,适合中小型项目。社区支持丰富,生态完善。

4.3前端技术栈

1. Vue.js

构建动态的、响应式的单页面应用 (SPA)。数据绑定简单,组件化开发高效。支持 MVVM 模型,视图和数据逻辑分离。

2. Axios

处理 HTTP 请求,用于与后端 API 通信。提供更简洁的 API 调用方式。支持请求拦截器和响应拦截器。

3. HTML + CSS

构建页面结构和样式。使用现代化的 CSS(如 Flexbox 和 Grid)创建响应式布局。加载 Google 字体和自定义样式,提升用户体验。

4.4其他

4.4.1. ObjectMapper

在后端将 JSON 转换为 Java 对象,或将 Java 对象转换为 JSON。简化数据格式转换。减少手动解析 JSON 的复杂性。

4.4.2. 静态资源

通过 index.html 提供用户界面。使用 Vue.js 和 Axios 实现动态交互。提供直观的用户体验。

5.参考文献

springboot官方文档
SpringBoot(看这一篇就够了)
【如何修改配置Maven镜像?】
CSS彈性盒子用法

...全文

相关推荐

Personal-Tech-Blog:使用Java Spring Boot框架+ MySQL数据库+语义UI前端UI框架构建自己的个人技术博客

个人技术博客 使用Java Spring Boot框架+ MySQL数据库+语义UI前端UI框架来构建您自己的个人技术博客。 可以通过访问该网站演示

任念辰

基于Spring Boot的个人博客系统设计与实现:涵盖VUE、MySQL、Layui技术栈

内容概要:本文档介绍了基于Spring Boot的个人博客系统的设计与实现。该系统设有管理员、用户和博主三种角色,各具不同的功能权限。管理员负责系统管理和内容审核,博主可以发布和管理文章,用户则能浏览、收藏和评论文章。系统采用Spring Boot作为后端框架,前端使用Vue.js和Layui,数据库选用MySQL。文档详细描述了系统的需求分析、设计、实现和测试过程,强调了系统在功能性和性能上的优化,确保良好的用户体验。此外,还对开发过程中遇到的挑战和解决方案进行了总结。 适合人群:具有一定编程基础,特别是对Web开发有兴趣的研发人员,尤其是使用Java和Spring生态系统的开发者。 使用场景及目标:①了解如何使用Spring Boot快速搭建Web应用;②掌握前后端分离架构的设计与实现;③学习如何利用Vue.js和Layui构建动态、交互式的前端页面;④掌握MySQL数据库的设计与优化技巧;⑤熟悉系统测试的方法与流程,确保软件质量。 其他说明:本文档不仅提供了技术实现的详细介绍,还分享了作者在开发过程中的心得体会,包括需求分析的重要性、模块化编程的优势以及持续学习和改进的价值。对于希望深入理解Web开发全流程的读者来说,是一份非常有价值的参考资料。

扫地僧009

极其简易的个人博客系统,技术栈Spring Boot、MyBatis、Redis、Vue.zip

【博客个人资源】 包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

枫蜜柚子茶

毕业设计&课设-基于Spring Boot技术的个人博客,含前后台功能及安装说明.zip

该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过严格测试运行成功才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

pk_xz123456

毕业设计&课设-极其简易的个人博客系统,技术栈Spring Boot、MyBatis、Redis、Vue适合初学者参考.zip

该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

毕业小助手
评论
收藏 已收藏
分享
返回顶部