60. 【Java】阶段实战:个人博客项目(上)

搭建个人博客流程记录 目录 一、购买阿里云服务器(60多块够了先买1个月) 二、基于LNMP和Wordpress搭建个人博客 1.下载并解压LNMP包 2.安装WordPress 这是我搭的先放出来给大家参观下......我的博客 一、购买阿里云服务器(60多块够了先买1个月) 学生的话购买1年的学生优惠,可以直接选择使用wordpress镜像,但是建议选CentOS系统自己安装wordpress不然挺多... 阅读详情

摘要: 本文是个人博客项目的上篇,详细讲解如何使用Spring Boot 3.4、JPA、PostgreSQL和Thymeleaf等技术栈搭建博客系统的后端基础。内容涵盖需求分析、技术选型、数据库设计、项目初始化、实体层和Repository层的完整实现,并提供了可运行的代码示例和初始化数据脚本,帮助Java开发者快速掌握全栈项目开发的核心流程。

关键词: Spring Boot, JPA, PostgreSQL, 个人博客系统, 全栈开发


经过前面五十九篇文章的积累,你已经从“Java 小白”成长为了一名掌握了 Java 核心语法、面向对象、集合框架、I/O、并发编程、网络编程、单元测试、日志、JDBC、Spring Boot 的开发者。可以说,你已经有了一个相当完整的 Java 技能树。

但技能树再茂盛,如果不结出果实,也只是好看的装饰。今天,我们要做的事就是把之前学到的所有知识——Spring Boot、JPA、数据库、Maven、日志、单元测试——全部放到一个真正的项目中,从零开始构建一个完整的个人博客系统。

这个项目将分为两篇文章:

  • 上篇(今天):需求分析、技术选型、数据库设计、项目初始化、实体层和 Repository 层。
  • 下篇(下一篇):业务逻辑层(Service)、控制器层(Controller)、前端页面、安全控制、项目打包与部署。

今天,我们就先搭好整个项目的“地基”。


1. 需求分析 —— 一个博客应该有哪些功能?

在写代码之前,我们先把需求想清楚。一个个人博客,最核心的功能当然是写文章和看文章。但为了让项目更丰满,我们给它加上分类、标签、评论和用户认证。

功能列表:

模块功能说明
文章管理发布文章管理员可以写新文章,包含标题、内容、分类、标签
编辑文章修改已发布的文章
删除文章删除文章(软删除或硬删除)
查看文章列表分页展示所有文章,按发布时间倒序
查看文章详情点击标题进入文章详情页,显示完整内容
按分类筛选点击某个分类,只显示该分类下的文章
按标签筛选点击某个标签,只显示包含该标签的文章
搜索文章按标题关键词搜索
分类管理增删改查管理博客的分类(如“Java”、“生活”、“思考”)
标签管理增删改查管理博客的标签(如“Spring Boot”、“读书笔记”)
评论管理发表评论访客在文章下方发表评论
审核评论管理员审核评论(为简化,我们直接显示,不加审核)
用户认证登录管理员登录后才能进入后台管理
注销退出登录

为了让项目在合理的范围内完成,我们会做一些简化:

  • 只有管理员(一个用户)能写文章、管理分类和标签。
  • 评论不需要审核,直接显示。
  • 暂时不提供注册功能(管理员账号预先在数据库中创建)。

2. 技术选型 —— 用什么工具来搭建?

层次技术说明
后端框架Spring Boot 3.4当前最新稳定版,支持 JDK 21
ORM 框架Spring Data JPA (Hibernate)简化数据库操作,用注解映射实体
数据库PostgreSQL关系型数据库,存储所有数据
模板引擎Thymeleaf服务端渲染 HTML 模板
前端样式Bootstrap 5 + 原生 CSS快速搭建美观的界面
构建工具Maven依赖管理和构建
日志SLF4J + Logback项目日志记录
测试JUnit 5 + Spring Boot Test单元测试和集成测试

注:我们选择 Thymeleaf 作为模板引擎,而不是前后端分离(Vue/React),是因为这个系列的目标是让你理解“全栈”的概念——从数据库到前端页面,你都能掌控。Thymeleaf 是 Spring Boot 官方推荐的模板引擎,语法简单,和 Spring 集成得天衣无缝。


3. 数据库设计 —— 画出数据的“蓝图”

在写代码之前,我们先设计好数据库的表结构。

3.1 ER 图(概念设计)

我们需要的表有:

  • t_user:用户表(管理员)
  • t_category:分类表
  • t_tag:标签表
  • t_article:文章表
  • t_comment:评论表
  • t_article_tag:文章-标签关联表(多对多)
3.2 详细的表结构

① 用户表(t_user)

字段名类型说明
idBIGINT主键,自增
usernameVARCHAR(50)用户名,唯一
passwordVARCHAR(100)密码(存储加密后的值)
emailVARCHAR(100)邮箱
avatarVARCHAR(200)头像 URL
created_atDATETIME创建时间

② 分类表(t_category)

字段名类型说明
idBIGINT主键,自增
nameVARCHAR(50)分类名称,唯一
slugVARCHAR(50)URL 友好别名(如 “java”)
created_atDATETIME创建时间

③ 标签表(t_tag)

字段名类型说明
idBIGINT主键,自增
nameVARCHAR(50)标签名称,唯一
created_atDATETIME创建时间

④ 文章表(t_article)

字段名类型说明
idBIGINT主键,自增
titleVARCHAR(200)文章标题
slugVARCHAR(200)URL 友好别名
summaryVARCHAR(500)文章摘要
contentLONGTEXT文章正文(Markdown 格式)
cover_imageVARCHAR(200)封面图片 URL
view_countINT浏览次数
category_idBIGINT外键,指向分类表
user_idBIGINT外键,指向用户表(作者)
statusTINYINT状态:0-草稿,1-已发布
is_topBOOLEAN是否置顶
created_atDATETIME创建时间
updated_atDATETIME更新时间
published_atDATETIME发布时间

⑤ 评论表(t_comment)

字段名类型说明
idBIGINT主键,自增
article_idBIGINT外键,指向文章表
author_nameVARCHAR(50)评论者姓名
author_emailVARCHAR(100)评论者邮箱
contentVARCHAR(1000)评论内容
created_atDATETIME创建时间
is_approvedBOOLEAN是否审核通过(本项目中默认 true)

⑥ 文章-标签关联表(t_article_tag)

字段名类型说明
article_idBIGINT外键,指向文章表
tag_idBIGINT外键,指向标签表

这是一个多对多关系,所以需要一张中间表。


4. 创建 Spring Boot 项目

4.1 在 Spring Initializr 中创建项目
  1. 访问 https://start.spring.io 或使用 IDEA 的 Spring Initializr。
  2. 填写项目信息:
    • Group:com.example
    • Artifact:blog
    • Name:blog
    • Description:个人博客系统
    • Package name:com.example.blog
    • Packaging:Jar
    • Java:21
  3. 添加依赖(在 Dependencies 中搜索并勾选):
    • Spring Web:Web 应用基础
    • Spring Data JPA:JPA 数据库访问
    • Thymeleaf:模板引擎
    • PostgreSQL Driver:PostgreSQL 驱动
    • Lombok:简化 getter/setter(可选)
    • Spring Boot DevTools:热加载(开发时方便)
    • Spring Security:用户认证(可选,我们后面会加)
  4. 点击 Generate 下载项目,解压后在 IDEA 中打开。
4.2 查看 pom.xml

关键的依赖部分应该长这样:

<dependencies>
    <!-- Web 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Thymeleaf 模板引擎 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- PostgreSQL 驱动 -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
    <!-- 测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
4.3 配置数据库连接

在 src/main/resources 目录下,把 application.properties 重命名为 application.yml(YAML 格式更清晰),然后写入:

# 服务器配置
server:
  port: 8080

# 数据库配置
spring:
  datasource:
    # PostgreSQL 连接 URL
    url: jdbc:postgresql://localhost:5432/blog?serverTimezone=Asia/Shanghai&characterEncoding=utf8
    username: pgsql     # PostgreSQL 默认超级用户通常是 postgres
    password: pgsql     # 修改为你本地 PostgreSQL 的密码
    driver-class-name: org.postgresql.Driver

  # JPA 配置
  jpa:
    hibernate:
      ddl-auto: update   # 自动创建/更新表结构(开发阶段用 update,生产环境用 none)
    show-sql: true        # 控制台显示 SQL 语句
    properties:
      hibernate:
        format_sql: true  # 格式化 SQL 输出
        dialect: org.hibernate.dialect.PostgreSQLDialect

  # Thymeleaf 配置
  thymeleaf:
    cache: false          # 开发阶段关闭模板缓存,方便修改立即生效
    encoding: UTF-8
    mode: HTML

  # 日志配置
logging:
  level:
    com.example.blog: DEBUG
    org.springframework.web: INFO

在 PostgreSQL 中创建数据库:

CREATE DATABASE IF NOT EXISTS blog;

5. 创建实体类(Entity)

在 com.example.blog.entity 包下创建所有实体类。我们使用 JPA 注解来映射表和字段。

5.1 基础实体类(BaseEntity)

为了统一管理 created_at 和 updated_at,我们创建一个基类:

package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @UpdateTimestamp
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
}
  • @MappedSuperclass:这个类不会被映射成数据库表,但它的字段会被子类继承。
  • @CreationTimestamp:Hibernate 会在插入时自动设置时间。
  • @UpdateTimestamp:Hibernate 会在更新时自动更新时间。
5.2 用户实体(User)
package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_user")
public class User extends BaseEntity {

    @Column(nullable = false, unique = true, length = 50)
    private String username;

    @Column(nullable = false, length = 100)
    private String password;

    @Column(length = 100)
    private String email;

    @Column(length = 200)
    private String avatar;

    // 一个用户可以发布多篇文章
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Article> articles = new ArrayList<>();
}
5.3 分类实体(Category)
package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_category")
public class Category extends BaseEntity {

    @Column(nullable = false, unique = true, length = 50)
    private String name;

    @Column(unique = true, length = 50)
    private String slug;   // URL 友好的别名,如 "java"

    // 一个分类下有多篇文章
    @OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
    private List<Article> articles = new ArrayList<>();
}
5.4 标签实体(Tag)
package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_tag")
public class Tag extends BaseEntity {

    @Column(nullable = false, unique = true, length = 50)
    private String name;

    // 多对多关系:一个标签可以属于多篇文章
    @ManyToMany(mappedBy = "tags")
    private List<Article> articles = new ArrayList<>();
}
5.5 文章实体(Article)—— 核心
package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_article")
public class Article extends BaseEntity {

    @Column(nullable = false, length = 200)
    private String title;

    @Column(unique = true, length = 200)
    private String slug;

    @Column(length = 500)
    private String summary;

    @Column(columnDefinition = "TEXT")
    private String content;

    @Column(name = "cover_image", length = 200)
    private String coverImage;

    @Column(name = "view_count")
    private Integer viewCount = 0;

    @Column(name = "status")
    private Integer status = 1;  // 0-草稿,1-已发布

    @Column(name = "is_top")
    private Boolean isTop = false;

    @Column(name = "published_at")
    private LocalDateTime publishedAt;

    // ---- 关联关系 ----

    // 多对一:一篇文章属于一个分类
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id")
    private Category category;

    // 多对一:一篇文章属于一个作者
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User author;

    // 多对多:一篇文章可以有多个标签
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
        name = "t_article_tag",
        joinColumns = @JoinColumn(name = "article_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private List<Tag> tags = new ArrayList<>();

    // 一对多:一篇文章有多条评论
    @OneToMany(mappedBy = "article", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Comment> comments = new ArrayList<>();
}
5.6 评论实体(Comment)
package com.example.blog.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_comment")
public class Comment extends BaseEntity {

    @Column(name = "author_name", nullable = false, length = 50)
    private String authorName;

    @Column(name = "author_email", length = 100)
    private String authorEmail;

    @Column(nullable = false, length = 1000)
    private String content;

    @Column(name = "is_approved")
    private Boolean isApproved = true;

    // 多对一:一条评论属于一篇文章
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "article_id")
    private Article article;
}

6. 创建 Repository 接口

在 JPA 中,Repository 接口负责数据访问。我们不需要写实现类——Spring Data JPA 会在运行时自动生成。

在 com.example.blog.repository 包下创建:

package com.example.blog.repository;

import com.example.blog.entity.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {

    // 根据 slug 查询文章(用于 URL 访问)
    Optional<Article> findBySlug(String slug);

    // 分页查询已发布的文章(按发布时间倒序)
    Page<Article> findByStatusOrderByPublishedAtDesc(Integer status, Pageable pageable);

    // 查询某个分类下的已发布文章(分页)
    Page<Article> findByCategoryIdAndStatusOrderByPublishedAtDesc(
        Long categoryId, Integer status, Pageable pageable
    );

    // 查询包含某个标签的已发布文章(分页)
    @Query("SELECT a FROM Article a JOIN a.tags t WHERE t.id = :tagId AND a.status = :status ORDER BY a.publishedAt DESC")
    Page<Article> findByTagIdAndStatus(@Param("tagId") Long tagId, @Param("status") Integer status, Pageable pageable);

    // 按标题关键词搜索已发布文章(分页)
    @Query("SELECT a FROM Article a WHERE a.status = :status AND a.title LIKE CONCAT('%', :keyword, '%') ORDER BY a.publishedAt DESC")
    Page<Article> searchByKeyword(@Param("keyword") String keyword, @Param("status") Integer status, Pageable pageable);

    // 获取置顶的文章
    List<Article> findByIsTopTrueAndStatusOrderByPublishedAtDesc(Integer status);

    // 统计某个分类下的文章数
    Long countByCategoryId(Long categoryId);
}

同样,创建其他 Repository:

// UserRepository.java
package com.example.blog.repository;

import com.example.blog.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

// CategoryRepository.java
package com.example.blog.repository;

import com.example.blog.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
    Optional<Category> findBySlug(String slug);
    Optional<Category> findByName(String name);
}

// TagRepository.java
package com.example.blog.repository;

import com.example.blog.entity.Tag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface TagRepository extends JpaRepository<Tag, Long> {
    Optional<Tag> findByName(String name);
}

// CommentRepository.java
package com.example.blog.repository;

import com.example.blog.entity.Comment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
    // 按文章 ID 查询评论(按创建时间倒序)
    Page<Comment> findByArticleIdOrderByCreatedAtDesc(Long articleId, Pageable pageable);
}

7. 初始化数据 —— 启动时插入示例数据

为了让项目一启动就有数据可以展示,我们创建一个 DataInitializer 组件,在应用启动时插入默认的管理员账号、分类、标签和示例文章。

package com.example.blog;

import com.example.blog.entity.*;
import com.example.blog.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class DataInitializer implements CommandLineRunner {

    private final UserRepository userRepository;
    private final CategoryRepository categoryRepository;
    private final TagRepository tagRepository;
    private final ArticleRepository articleRepository;

    @Override
    public void run(String... args) {
        // 如果已经有用户,说明数据已初始化,跳过
        if (userRepository.count() > 0) {
            log.info("数据已存在,跳过初始化");
            return;
        }

        log.info("开始初始化示例数据...");

        // 1. 创建管理员用户
        User admin = new User();
        admin.setUsername("admin");
        // 实际项目中密码需要加密,这里先用明文(后面会改成加密)
        admin.setPassword("admin123");
        admin.setEmail("admin@blog.com");
        admin.setAvatar("https://i.pravatar.cc/150?img=1");
        userRepository.save(admin);
        log.info("已创建管理员用户: admin/admin123");

        // 2. 创建分类
        Category javaCat = createCategory("Java", "java");
        Category lifeCat = createCategory("生活随笔", "life");
        Category techCat = createCategory("技术杂谈", "tech");
        List<Category> categories = List.of(javaCat, lifeCat, techCat);
        categoryRepository.saveAll(categories);
        log.info("已创建 {} 个分类", categories.size());

        // 3. 创建标签
        Tag springTag = createTag("Spring");
        Tag jvmTag = createTag("JVM");
        Tag readingTag = createTag("读书笔记");
        Tag thinkingTag = createTag("思考");
        List<Tag> tags = List.of(springTag, jvmTag, readingTag, thinkingTag);
        tagRepository.saveAll(tags);
        log.info("已创建 {} 个标签", tags.size());

        // 4. 创建示例文章
        Article article1 = createArticle(
            "Spring Boot 从入门到精通",
            "spring-boot-tutorial",
            "Spring Boot 是 Java 后端开发中最流行的框架之一。本文带你从零开始,全面掌握 Spring Boot。",
            """
            # Spring Boot 从入门到精通

            Spring Boot 是 Spring 框架的"一键启动"版本,它让 Java Web 开发变得前所未有的简单。

            ## 什么是 Spring Boot?

            Spring Boot 的核心是"约定大于配置"——它为你提供了合理的默认配置,让你只需要关注业务逻辑。

            ## 为什么选择 Spring Boot?

            - 自动配置
            - 内嵌服务器
            - 生产就绪
            - 活跃的社区

            如果你想快速构建一个 Java Web 应用,Spring Boot 是最佳选择。
            """,
            javaCat,
            List.of(springTag, jvmTag),
            admin
        );

        Article article2 = createArticle(
            "JVM 内存模型深度解析",
            "jvm-memory-model",
            "理解 JVM 的内存结构是 Java 程序员进阶的必修课。本文带你深入 JVM 内部。",
            """
            # JVM 内存模型深度解析

            JVM(Java 虚拟机)是 Java 程序运行的基础。理解 JVM 的内存模型,有助于我们写出高性能、无内存泄漏的程序。

            ## 运行时数据区

            JVM 的内存主要分为以下几个区域:

            1. **堆(Heap)**:存放所有对象实例
            2. **方法区(Method Area)**:存放类信息、常量、静态变量
            3. **虚拟机栈(VM Stack)**:存放局部变量、方法调用
            4. **程序计数器(PC Register)**:记录当前线程执行的字节码行号

            掌握这些区域的作用和调优方法,是 Java 进阶的关键一步。
            """,
            techCat,
            List.of(jvmTag, thinkingTag),
            admin
        );

        Article article3 = createArticle(
            "2024 年读书笔记:年度 Top 10",
            "reading-list-2024",
            "2024 年我读了 50 本书,从中精选了 10 本,推荐给喜欢阅读的你。",
            """
            # 2024 年读书笔记:年度 Top 10

            读书是成本最低的自我投资。2024 年我读了 50 本书,下面是我的 Top 10 推荐。

            ## Top 1:《人类群星闪耀时》
            茨威格的经典之作,14 个改变人类命运的历史瞬间,读来令人心潮澎湃。

            ## Top 2:《你当像鸟飞往你的山》
            一个从垃圾堆里爬出来的女孩,最终走向剑桥博士的故事。教育的力量令人震撼。

            ## Top 3:《活着》
            余华的经典,读完后你会对"活着"这两个字有全新的理解。
            """,
            lifeCat,
            List.of(readingTag, thinkingTag),
            admin
        );

        articleRepository.saveAll(List.of(article1, article2, article3));
        log.info("已创建 {} 篇示例文章", 3);

        log.info("示例数据初始化完成!");
        log.info("访问 http://localhost:8080 查看博客");
        log.info("后台管理: http://localhost:8080/admin/login");
    }

    private Category createCategory(String name, String slug) {
        Category category = new Category();
        category.setName(name);
        category.setSlug(slug);
        return category;
    }

    private Tag createTag(String name) {
        Tag tag = new Tag();
        tag.setName(name);
        return tag;
    }

    private Article createArticle(String title, String slug, String summary, String content,
                                  Category category, List<Tag> tags, User author) {
        Article article = new Article();
        article.setTitle(title);
        article.setSlug(slug);
        article.setSummary(summary);
        article.setContent(content);
        article.setCategory(category);
        article.setTags(tags);
        article.setAuthor(author);
        article.setStatus(1);  // 已发布
        article.setPublishedAt(LocalDateTime.now());
        article.setViewCount(0);
        article.setIsTop(false);
        return article;
    }
}

8. 启动并验证

现在,所有准备工作已经完成!让我们启动应用:

  1. 确保 PostgreSQL 服务正在运行,并且数据库 blog 已经创建。
  2. 在 IDEA 中运行 BlogApplication 的 main 方法。
  3. 观察控制台日志,如果看到 “示例数据初始化完成” 的日志,说明数据已经成功插入。

此时,数据库中的表已经自动创建(因为 ddl-auto: update),示例数据也已经插入。

你可以用 PostgreSQL 客户端查看数据:

SELECT * FROM t_user;
SELECT * FROM t_category;
SELECT * FROM t_tag;
SELECT * FROM t_article;

如果一切正常,你就有了一个包含三篇示例文章的博客系统后端。只是现在还缺一个前端页面来展示它们。


9. 今天的总结

今天我们完成了个人博客项目的“地基”:

步骤内容
需求分析明确了文章、分类、标签、评论、用户认证五大模块
技术选型Spring Boot 3 + JPA + Thymeleaf + PostgreSQL+ Bootstrap
数据库设计设计了 6 张表,覆盖所有业务需求
项目创建用 Spring Initializr 创建了 Spring Boot 项目
实体类用 JPA 注解创建了 6 个实体类,建立了表之间的关联
Repository创建了 5 个 Repository 接口,定义了常用的数据访问方法
数据初始化在应用启动时自动插入管理员、分类、标签和示例文章

你的项目现在已经可以启动,数据也已经就位。但如果你现在访问 http://localhost:8080,只会看到一个默认的 Whitelabel Error Page——因为我们还没有写 Controller 和前端页面。

下一篇文章,我们会:

  • 创建 Service 层(业务逻辑)
  • 创建 Controller 层(处理 HTTP 请求)
  • 创建 Thymeleaf 模板(前端页面)
  • 集成 Spring Security(登录认证)
  • 完成项目打包与部署

整个博客就会从“数据存在但看不到”变成“一个真正可以访问的网站”。


动手试试

  1. 按照本文步骤,在你的电脑上创建这个博客项目,确保能成功启动,并且数据库中生成了所有表。

  2. 用 PostgreSQL 客户端查询 t_article 表,确认三篇示例文章已成功插入。

  3. 打开 application.yml,把 spring.jpa.show-sql 改为 true,然后重新启动应用,观察控制台输出的 SQL 语句,感受 JPA 是如何自动生成 SQL 的。

  4. (挑战)尝试添加一个 @RestController 来测试数据:创建一个 TestController,在 @GetMapping("/test/articles") 中返回 articleRepository.findAll(),看看能否通过浏览器看到 JSON 格式的文章列表。

我们下一篇见——这个博客很快就会变成一个真正的网站了!😃

📌 获取本系列示例代码请访问 GitCode。

Vue+SpringBoot个人博客项目实战:从零搭建到部署全流程 前后端分离架构是现代Web应用开发的主流模式,它将前端交互与后端服务解耦,通过RESTful API通信,既提升了开发效率,也便于独立部署和扩展。在个人博客这类业务场景中,实现这一架构需要掌握Vue Router路由控制、Pinia状态管理、axios请求封装,以及SpringBoot接口设计、JWT鉴权和MyBatis-Plus持久化等关键技术。同时,生产环境还要面对XSS攻击防护、m3u8视频播放等实际问题,这些都是工程实践中的高频需求。本文以个人博客项目为载体,完整梳理从技术选型、数据库建模、前后端联 阅读详情

相关推荐

IOPaint模型部署教程

IOPaint是一款功能全面且强大的AI图像处理工具,它不仅免费开源,还由SOTA(State-of-the-Art,即最先进)AI模型驱动,为图像编辑和修复带来了前所未有的便利和高效。以下是对IOPaint的详细介绍:

SJJS_1的博客 1540

个人博客系统整体介绍

1、项目简介 在网上看了很多别人的个人博客,觉得很华丽,逼格很高,于是我也想搞一个玩玩,但是我吧,前端又不怎么会,于是就在B站找了个写博客的教程,先依样画葫芦弄个原型出来,别说,也不丑,能看,界面如下: ...

AlaGeek的博客 1万+

Habitat安装全网最详细教程,手把手带你跑通example.py(全网唯一)

全网最详细具身智能仿真平台habitat的安装教程

shannanshouyin的博客 2754

60s 用Docker搭建一套博客系统

微信公众号:Java编程之道 关注可解锁更多Java开发知识。问题或建议,欢迎公众号留言 ???? 如果你觉得本文对你有帮助,欢迎赞赏 60秒 搭建博客系统 哈,出差回来后调整了一段时间,突然不知道为大家分享些什么了,因为这些事情前期定下的一些计划也不能正常推进(康同学最近也很忙)。但是,文章还得接着写,学习可不能断。 由于工作的原因,个人可能不能持续为大家输出基于Java的技术,因为近期都在做Golang开发,个人精力有限没法做到声东击西????。铁子,别走!我又没说不写文章了。???? 因为我们这个

LeoByte的编程驿站 1225

从原理到实战:ARS548 4D毫米波雷达数据处理与多模态融合全解析

本文深入解析了4D毫米波雷达ARS548的工作原理与数据处理全流程。从FMCW测距测速、MIMO虚拟天线阵列到点云生成的三步FFT处理,提供了详尽的Python代码实现。文章进一步探讨了与激光雷达、相机的多模态时空对齐与融合策略,并指导如何构建用于自动驾驶感知训练的多模态标注数据集,为相关算法工程师提供了从理论到实践的完整指南。

weixin_29161719的博客 364

图像评价之计算PSNR、SSIM、MSE、LPIPS和NIQE评价指标

如果代码对你的研究有所帮助,请为该仓库点上小星星。

书山有路,学海无涯! 2637

ssm个人博客网站(开题+源码)

同时,通过优化个人博客网站的功能与服务,可以提高用户体验,促进个体之间的互动与交流,进而推动社会的进步。此外,对于博客系统的深入研究,可以为其他类似系统的设计与开发提供宝贵的经验。在这样的背景下,深入研究个人博客网站的建设与发展,对于推动网络文化建设、促进社会交流具有深远的意义。本研究旨在深入剖析个人博客网站的核心功能与特点,挖掘用户需求,探究其在信息传播、文化交流中的作用。同时,通过对现有博客系统的分析,寻找其存在的问题与不足,提出改进建议与创新点,以期为个人博客网站的长远发展提供理论支持与实践指导。

2301_81685385的博客 884

紫光同创PGL50H开发板实战:盘古50KN网口板的高速通信与数据处理

本文详细介绍了紫光同创PGL50H开发板(盘古50KN网口板)在高速通信与数据处理领域的实战应用。文章从开箱、核心芯片解析、开发环境搭建入手,重点讲解了如何配置与测试其8路千兆以太网接口和SFP光纤接口,并深入探讨了FPGA与DDR3协同进行多路数据汇聚处理的系统架构与调试方法,为网络通信与高速数据处理系统开发提供了宝贵的实践经验。

weixin_28256233的博客 450

docker: 未找到命令_60s 用Docker搭建一套博客系统

先赞后看,养成习惯欢迎微信关注 Java编程之道每天进步一点点,沉淀技术分享知识。60秒 搭建博客系统哈,出差回来后调整了一段时间,突然不知道为大家分享些什么了,因为这些事情前期定下的一些计划也不能正常推进(康同学最近也很忙)。但是,文章还得接着写,学习可不能断。由于工作的原因,个人可能不能持续为大家输出基于Java的技术,因为近期都在做Golang开发,个人精力有限没法做到声东击西。铁子,别走!...

weixin_30082413的博客 2029

手把手教你设计热电偶信号采集电路:从运放选型到ADC配置全流程

本文详细解析了热电偶信号采集电路的设计全流程,重点涵盖从高精度运放选型、差分放大电路设计到ADC配置与软件处理的工程实践。针对热电偶输出的微弱毫伏级差分信号,文章深入探讨了如何克服噪声、实现冷端补偿,并提供了具体的器件选型建议与电路调试技巧,旨在帮助工程师构建稳定可靠的高精度温度测量系统。

weixin_29169899的博客 415

# 【WorkBuddy专栏33】工作空间,最大的WorkBuddy技巧——任务隔离、记忆分区与多项目管理实战

工作空间,最大的WorkBuddy技巧——任务隔离、记忆分区与多项目管理实战

AI人人懂 2101

基于java的个人博客系统(源码+开题)

研究内容: 本研究的内容主要包括以下几个方面:首先,我们需要对现有的个人博客系统进行深入的研究和分析,了解其优缺点;最后,我们需要对新设计的系统进行评估和优化,以满足用户的需求和提升系统的使用体验。然而,目前市面上的个人博客系统功能相对单一,用户体验不佳,无法满足博主和读者的需求。通过对系统的研究和设计,我们希望能够为博主提供一个高效、便捷的博客管理工具,从而推动个人博客的发展和创新。2023年1月9日-2023年3月10日:收集相关资料,设计架构方案,完成数据库系统的设计,编写实现相关模块的功能;

基努毕设程序 541

第14.1章 高翔博士2025年11月最新开源框架Lightning-LM源码学习解读(一):激光-IMU定位+建图算法各模块简介

Lightning-LM:高效激光SLAM定位系统 该框架基于模块化设计,通过激光-IMU融合实现快速建图与定位,核心特点包括: 极速性能:纯CPU运行(建图1.2核/定位0.8核) 模块化架构:包含激光里程计(LIO)、地图管理、回环检测等独立模块 动态场景支持:地图分块加载、动静态图层分离 多模式适配:支持ROS2环境下的在线/离线运行 关键模块包括前端里程计(core/lio)、2D/3D地图转换(core/g2p5)、轻量优化库(core/miao)等,通过系统控制器(core/system)协调流

行知SLAM 2434

Java基于Web的个人博客(开题+源码)

然而,尽管网络博客的应用越来越广泛,但在博客系统的设计和使用中,仍然存在一些问题需要解决。研究目的:本研究的目的是设计和实现一个基于Web的个人博客系统,以提高博客系统的使用体验和博主的管理效率。具体来说,本研究将实现以下功能:用户注册登录、博主管理自己的博客、文章的分类、相册的管理、访问统计等。研究意义:对于用户而言,博客系统的使用体验直接影响到用户的使用意愿和博客的质量。同时,对于博主而言,如何有效地管理自己的博客,包括文章的分类、相册的管理等,也是当前博主面临的重要问题。

qh602的博客 408

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ssm个人博客(开题+源码)

对个人博客的研究不仅能深化我们对这一领域的认识,还能为博客的创建者、使用者和管理者提供实践指导。最后,从学术角度看,个人博客的研究有助于填补相关领域的理论空白,为其他网络媒体的研究提供参考。随着互联网的普及和社交媒体的兴起,个人博客已经从单一的日记形式转变为多元化、个性化的内容分享平台。本研究旨在系统地探索个人博客的特性和发展趋势,通过深入分析博主、博客文章、博文分类、博客视频等系统功能,揭示个人博客的内在规律和外部影响。第 3 阶段:2022年8月-12月系统设计及实现,根据完成情况着手论文撰写。

sryue06的博客 776

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【Java学习路线| 最佳食用指南 60days】

60days 每天10h以上时间 笔记知识点熟悉 附录面试题掌握 以下技术栈可牢固掌握。

King_model的博客 1369

java计算机毕业设计个人博客系统(附源码+springboot+开题+论文+部署)

本研究的意义在于通过设计和实现一个功能丰富、个性化的个人博客系统,为用户提供一个自由表达、分享交流的平台。该系统的开发不仅能够满足用户对于博客创作和分享的需求,还能提升用户的网络体验,促进网络文化的繁荣发展。通过本系统的开发,希望能够提升用户的网络创作热情,促进网络文化的交流与传播,为用户带来更好的网络体验。博客文章发布功能是本系统的核心之一。综上所述,本研究将围绕个人博客系统的设计与实现展开,通过构建用户管理、文章分类以及博客文章发布等核心功能模块,为用户提供一个功能全面、操作便捷、个性化的博客平台。

杰简程序毕设 874

【身如苔米,心向高山】我的 2024 博客总结:记录平凡路上的微光

2024我的博客历程总结

GGBond778的博客 2162

【个人博客搭建练手版】Windows环境下使用tale,mblog,halo三种框架搭建个人博客,适合准备搭建博客的练手之作

在Windows环境下使用tale,mblog,halo搭建个人博客练手之作

weixin_48668564的博客 1617

Java:60-项目上线部署

查看tomcat是否能够正常启动: 关闭防火墙: 其实mysql -u用户名 -p密码,中的用户名和密码可以与对应的-u和-p不用空格隔开 登录MySQL,检查数库连接是否正常: 使用SQLYog连接Linux上的MySQL, 导入SQL脚本 创建项目所需的数据库: 修改后启动项目,测试一下 保证数据库连接没有问题 执行打包命令: 复制出target目录下的 war包: war包存放在服务器中,启动服务器或者访问时都会解压对应war包 前端项目部署: 修改配置文件: 前端项目的配置文件有两个,

qq_59609098的博客 3993

SpringBoot+Vue 博客系统(一):个人网站的由来

我想,每个程序员都想做一个自己的网站吧。最起码,我是这样想的

YangCunle的博客 679

java计算机毕业设计个人博客网站源码+mysql数据库+系统+lw文档+部署

java计算机毕业设计个人博客网站源码+mysql数据库+系统+lw文档+部署。前端技术:Layui、HTML、CSS、JS、JQuery等技术。JSP教学视频点播系统的设计与实现SQLServer。jsp基于Web的电子邮件系统xns程序论文开题。ssm基于javaweb的家庭财务管理系统。ssm基于SSM框架的学习资料校内共享平台。ssm基于Android平台的球鞋销售系统。

m0_73366195的博客 271

java计算机毕业设计个人博客系统开(开题+程序+论文)

本研究将围绕个人博客系统的核心功能展开,具体包括用户管理、博主分类、博主信息管理、文章分类与博文信息管理、标签分类管理、相册分类与相册信息管理、博客分类与博客信息管理以及博客统计等模块。博客,作为一种早期的网络日志形式,逐渐演变成了个人展示思想、分享知识与经验的重要平台。近年来,虽然社交媒体和短视频平台的兴起对博客产生了一定冲击,但博客以其独特的深度、专业性和持久性,依然吸引着大量热爱写作与深度阅读的用户。通过该系统,用户能够方便地创建个人博客、发布文章、管理相册与标签,同时享受与其他用户的互动与交流。

sryue06的博客 1473

【Java开发学习路线图】从入门到项目实战全攻略

基础语法 → 面向对象 → 集合/IO → 数据库 → Spring全家桶 → 项目实战(关注我,后续更新各阶段详细教程!

weixin_62922042的博客 1438

Spring AI + GPT-5.5 + Ollama 配置教程:Base URL、超时与流式调用

由于不同 Spring AI、Spring Boot 小版本之间仍可能存在差异,创建项目时应检查 Spring Initializr、Spring AI BOM 和官方兼容矩阵,不要直接复制旧教程中的 Starter 名称和版本号。多人项目最好隔离不同客户端,并在脱敏前提下记录最终 URL、状态码、请求耗时、请求 ID 和模型 ID。Spring AI 接入模型 API,至少要同时确认 Starter、Base URL、请求路径、API Key、模型 ID、连接超时、读取超时和流式客户端这 8 项。

2601_95893075的博客 215
上一篇: 59. 【Java】Spring Boot 入门:第一个 Web 应用
下一篇: 61. 【Java】阶段实战:个人博客项目(下)
gugucoding
博客等级 码龄140天 7粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值