Java 搭建个人博客基本框架
为了实现一个功能完善的个人博客系统,我们将使用Spring Boot作为框架,MySQL作为数据库,并引入Spring Security来处理用户认证和授权。以下是系统的详细设计和实现步骤:
## 项目结构
- `src/main/java/com/blog`
   - `controller`
   - `service`
   - `repository`
   - `model`
 - `src/main/resources`
   - `application.properties`
 - `pom.xml`
## 主要功能
1. 用户注册和登录
 2. 文章的增删改查(CRUD)
 3. 评论系统
 4. 标签系统
 5. 分页和搜索
 6. 富文本编辑器支持
## 项目初始化
### 1. `pom.xml` 配置
```xml
 <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
     </dependency>
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-validation</artifactId>
     </dependency>
 </dependencies>
 ```
### 2. `application.properties` 配置
```properties
 spring.datasource.url=jdbc:mysql://localhost:3306/blog
 spring.datasource.username=root
 spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
 spring.jpa.show-sql=true
 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
 ```
### 3. 数据库模型
#### 3.1 用户模型
```java
 @Entity
 public class User {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
    private String username;
     private String password;
     private String email;
    // Getters and Setters
 }
 ```
#### 3.2 文章模型
```java
 @Entity
 public class Post {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
    private String title;
     private String content;
     private LocalDateTime createdAt;
    @ManyToOne
     @JoinColumn(name = "user_id")
     private User user;
    @ManyToMany
     @JoinTable(
       name = "post_tag", 
       joinColumns = @JoinColumn(name = "post_id"), 
       inverseJoinColumns = @JoinColumn(name = "tag_id"))
     private Set<Tag> tags = new HashSet<>();
    // Getters and Setters
 }
 ```
#### 3.3 评论模型
```java
 @Entity
 public class Comment {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
    private String content;
     private LocalDateTime createdAt;
    @ManyToOne
     @JoinColumn(name = "post_id")
     private Post post;
    @ManyToOne
     @JoinColumn(name = "user_id")
     private User user;
    @ManyToOne
     @JoinColumn(name = "parent_comment_id")
     private Comment parentComment;
    @OneToMany(mappedBy = "parentComment", cascade = CascadeType.ALL)
     private List<Comment> replies = new ArrayList<>();
    // Getters and Setters
 }
 ```
#### 3.4 标签模型
```java
 @Entity
 public class Tag {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
private String name;
    @ManyToMany(mappedBy = "tags")
     private Set<Post> posts = new HashSet<>();
    // Getters and Setters
 }
 ```
### 4. 数据库仓库
#### 4.1 用户仓库
```java
 public interface UserRepository extends JpaRepository<User, Long> {
     Optional<User> findByUsername(String username);
 }
 ```
#### 4.2 文章仓库
```java
 public interface PostRepository extends JpaRepository<Post, Long> {
     Page<Post> findAll(Pageable pageable);
 }
 ```
#### 4.3 评论仓库
```java
 public interface CommentRepository extends JpaRepository<Comment, Long> {
     List<Comment> findByPostId(Long postId);
     List<Comment> findByParentCommentId(Long parentCommentId);
 }
 ```
#### 4.4 标签仓库
```java
 public interface TagRepository extends JpaRepository<Tag, Long> {
 }
 ```
### 5. 服务层
#### 5.1 用户服务
```java
 @Service
 public class UserService {
    @Autowired
     private UserRepository userRepository;
    @Autowired
     private PasswordEncoder passwordEncoder;
    public User save(User user) {
         user.setPassword(passwordEncoder.encode(user.getPassword()));
         return userRepository.save(user);
     }
    public Optional<User> findByUsername(String username) {
         return userRepository.findByUsername(username);
     }
 }
 ```
#### 5.2 文章服务
```java
 @Service
 public class PostService {
    @Autowired
     private PostRepository postRepository;
    public Post save(Post post) {
         post.setCreatedAt(LocalDateTime.now());
         return postRepository.save(post);
     }
    public Page<Post> findAll(Pageable pageable) {
         return postRepository.findAll(pageable);
     }
 }
 ```
#### 5.3 评论服务
```java
 @Service
 public class CommentService {
    @Autowired
     private CommentRepository commentRepository;
    public Comment save(Comment comment) {
         comment.setCreatedAt(LocalDateTime.now());
         return commentRepository.save(comment);
     }
    public List<Comment> findByPostId(Long postId) {
         return commentRepository.findByPostId(postId);
     }
    public List<Comment> findByParentCommentId(Long parentCommentId) {
         return commentRepository.findByParentCommentId(parentCommentId);
     }
 }
 ```
### 6. 控制器
#### 6.1 用户控制器
```java
 @Controller
 @RequestMapping("/users")
 public class UserController {
    @Autowired
     private UserService userService;
    @PostMapping("/register")
     public String register(@ModelAttribute User user) {
         userService.save(user);
         return "redirect:/login";
     }
 }
 ```
#### 6.2 文章控制器
```java
 @Controller
 @RequestMapping("/posts")
 public class PostController {
    @Autowired
     private PostService postService;
    @GetMapping
     public String list(Model model, Pageable pageable) {
         Page<Post> posts = postService.findAll(pageable);
         model.addAttribute("posts", posts);
         return "posts/list";
     }
    @PostMapping
     public String save(@ModelAttribute Post post) {
         postService.save(post);
         return "redirect:/posts";
     }
 }
 ```
#### 6.3 评论控制器
```java
 @Controller
 @RequestMapping("/comments")
 public class CommentController {
    @Autowired
     private CommentService commentService;
    @PostMapping
     public String save(@ModelAttribute Comment comment) {
         commentService.save(comment);
         return "redirect:/posts/" + comment.getPost().getId();
     }
 }
 ```
### 7. 前端模板(使用Thymeleaf)
#### 7.1 登录页面
```html
 <!DOCTYPE html>
 <html xmlns:th="http://www.thymeleaf.org">
 <head>
     <title>Login</title>
 </head>
 <body>
     <form th:action="@{/login}" method="post">
         <div>
             <label for="username">Username:</label>
             <input type="text" id="username" name="username" />
         </div>
         <div>
             <label for="password">Password:</label>
             <input type="password" id="password" name="password" />
         </div>
         <div>
             <button type="submit">Login</button>
         </div>
     </form>
 </body>
 </html>
 ```
#### 7.2 文章列表页面
```html
 <!DOCTYPE html>
 <html xmlns:th="http://www.thymeleaf.org">
 <head>
     <title>Posts</title>
 </head>
 <body>
     <div>
         <a th:href="@{/posts/new}">New Post</a>
     </div>
     <div>
         <ul>
             <li th:each="post : ${posts}">
                 <h2 th:text="${post.title}"></h2>
                 <p th:text="${post.content}"></p>
                 <p>By: <span th:text="${post.user.username}"></span></p>
                 <a th:href="@{/posts/{id}(id=${post.id})}">Read more</a>
             </li>
         </ul>
     </div>
 </body>
 </html>
 #### 7.3 文章详情页面
```html
 <!DOCTYPE html>
 <html xmlns:th="http://www.thymeleaf.org">
 <head>
     <title>Post Details</title>
 </head>
 <body>
     <h1 th:text="${post.title}"></h1>
     <p th:text="${post.content}"></p>
     <h2>Comments</h2>
     <div th:each="comment : ${comments}">
         <p th:text="${comment.content}"></p>
         <p>By: <span th:text="${comment.user.username}"></span></p>
         <div th:each="reply : ${comment.replies}">
             <p th:text="${reply.content}"></p>
             <p>By: <span th:text="${reply.user.username}"></span></p>
         </div>
         <form th:action="@{/comments}" method="post">
             <input type="hidden" th:value="${comment.id}" name="parentComment.id" />
             <textarea name="content"></textarea>
             <button type="submit">Reply</button>
         </form>
     </div>
 </body>
 </html>
 ### 8. 富文本编辑器支持
在Thymeleaf模板中添加TinyMCE的支持:
```html
 <!DOCTYPE html>
 <html xmlns:th="http://www.thymeleaf.org">
 <head>
     <title>New Post</title>
     <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js"></script>
     <script>
         tinymce.init({
             selector: '#content'
         });
     </script>
 </head>
 <body>
     <form th:action="@{/posts}" method="post">
         <div>
             <label for="title">Title:</label>
             <input type="text" id="title" name="title" />
         </div>
         <div>
             <label for="content">Content:</label>
             <textarea id="content" name="content"></textarea>
         </div>
         <div>
             <button type="submit">Save</button>
         </div>
     </form>
 </body>
 </html>
 ```
通过上述步骤,我们已经建立了一个功能完善的个人博客系统。这个系统包括用户注册和登录、文章的增删改查、评论和标签系统,以及富文本编辑器的支持。
相关文章:
Java 搭建个人博客基本框架
为了实现一个功能完善的个人博客系统,我们将使用Spring Boot作为框架,MySQL作为数据库,并引入Spring Security来处理用户认证和授权。以下是系统的详细设计和实现步骤: ## 项目结构 - src/main/java/com/blog - controller …...
停车场智能化管理:车位引导系统实现车位资源优化与数据分析
随着城市汽车保有量的不断增长,停车难问题日益凸显。尤其是在高峰时段,寻找停车位和取车成为了许多车主的头疼问题。为了解决这一难题,维小帮智能车位引导系统应运而生,它利用先进的技术手段,帮助车主快速找到停车位&a…...
梯度下降法
梯度下降法是一种在机器学习和深度学习中广泛使用的优化算法。它用于最小化某个函数,通常是损失函数或成本函数,通过迭代调整参数来找到函数的最小值点。梯度下降法的基本思想是从一个初始参数出发,沿着损失函数梯度(导数…...
【高考志愿】光学工程
目录 一、专业概述 二、专业特点 三、研究和就业方向 3.1 研究方向 3.2 就业方向 四、光学工程专业排名 高考志愿选择光学工程专业无疑是一项既具深度又富挑战性的明智之举。这个古老而充满魅力的专业,正逐渐崭露其在现代社会中的重要性与独特魅力。 一、专业…...
Golang | Leetcode Golang题解之第205题同构字符串
题目: 题解: func isIsomorphic(s, t string) bool {s2t : map[byte]byte{}t2s : map[byte]byte{}for i : range s {x, y : s[i], t[i]if s2t[x] > 0 && s2t[x] ! y || t2s[y] > 0 && t2s[y] ! x {return false}s2t[x] yt2s[y] …...
【Unity】RPG2D龙城纷争(五)关卡编辑器之地图编辑
更新日期:2024年6月25日。 项目源码:本章发布 索引 简介关卡编辑器窗口类(LevelEditor)一、定义关卡编辑器窗口类二、两种编辑模式三、地块编辑模式1.关卡模板2.打开编辑窗口3.编辑器基本属性4.地块模板5.重新生成地图6.地图刷子7.刷地块源码链接简介 关卡编辑器将是我们配…...
音视频入门基础:H.264专题(4)——NALU Header:forbidden_zero_bit、nal_ref_idc、nal_unit_type简介
音视频入门基础:H.264专题系列文章: 音视频入门基础:H.264专题(1)——H.264官方文档下载 音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...
基于深度学习的人脸关键点检测
1. 任务和目标 人脸关键点检测的主要任务是识别并定位人脸图像中的特定关键点,例如眼睛的角点、眉毛的顶点、鼻子的底端、嘴角等。这些关键点不仅能提供面部结构的几何信息,还可以用于分析表情、识别个体,甚至检测面部姿势。 2. 技术和方法…...
C++自定义智能指针
template <class T> class counted_ptr;// 智能指针引用计数类 template <class T> class Ref_Ptr {friend class counted_ptr<T>; private:T* m_pTtr; // 实际的指针size_t counted_ptr; // 引用计数Ref_Ptr(T* p);virtual ~Ref_Ptr(); };template <clas…...
一个合理的前端应用文件结构
在大型应用中,最关键且最具挑战性的方面之一就是拥有一个良好且合理的文件结构。在考虑通过微前端将代码库拆分成多个应用之前,可以遵循一些步骤来改善项目级别的架构,并在您考虑这一路径时使过渡更容易。 我们的目标是应用某种模块化方法&am…...
spring和springboot的关系是什么?
大家好,我是网创有方的站长,今天给大家分享下spring和springboot的关系是什么? Spring和Spring Boot之间的关系可以归纳为以下几个方面: 技术基础和核心特性: Spring:是一个广泛应用的开源Java框架&#…...
智慧校园-医务管理系统总体概述
智慧校园医务管理系统,作为校园健康管理体系的智能化升级,深度融合信息技术与医疗服务,为师生构筑起一道全方位的健康守护网。医务管理系统以提升校园医疗服务水平、优化健康管理流程为核心目标,通过一系列创新功能,确…...
AUTOSAR汽车电子嵌入式编程精讲300篇-智能网联汽车CAN总线-基于电压信号的CAN总线入侵检测系统设计与实现
目录 前言 入侵检测系统研究现状 入侵检测系统建模 CAN总线 入侵检测威胁模型 Deep SVDD模型 入侵检测系统方案设计 挑战和解决方案 差分信号的采集与处理 差分信号的特征提取 入侵检测模型的设计 入侵检测系统性能评估 实验环境设置 不同的车辆状态 不同数量的…...
BLACKBOX.AI:解锁编程学习新纪元,加速开发的AI得力助手
文章目录 💯BLACKBOX.AI 官网🍁1 BLACKBOX.AI 工具使用教程🍁2 BLACKBOX.AI工具使用界面介绍🍁3 Chat(聊天)功能🍁4 Explore (探索)功能💎4.1 Terminal(终端)功能💎4.2 Discover(发现)功能&…...
实验三 时序逻辑电路实验
仿真 链接:https://pan.baidu.com/s/1z9KFQANyNF5PvUPPYFQ9Ow 提取码:e3md 一、实验目的 1、通过实验,理解触发的概念,理解JK、D等常见触发器的功能; 2、通过实验,加深集成计数器功能的理解,掌…...
云计算基础技术
存储类技术 云上数据如何存储 存储介质的作用:数据存储是数据流在加工过程中产生的临时文件或加工过程中需要查找的信息。数据以某种格式记录在计算机内部或外部存储媒介上。为什么会出现云存储?在解决数据存储问题上,现有的云存储产品已经能够做到在效率和成本上…...
【动态规划】2306. 公司命名
本文涉及知识点 动态规划汇总 LeetCode 2306. 公司命名 给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下: 从 ideas 中选择 2 个 不同 名字,称为 ideaA 和 ideaB 。 交换 ideaA 和 ideaB 的首字母。 如果得到的两个新…...
熟练掌握爬虫技术
一、Crawler、Requests反爬破解 1. HTTP协议与WEB开发 1. 什么是请求头请求体,响应头响应体 2. URL地址包括什么 3. get请求和post请求到底是什么 4. Content-Type是什么1.1 简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)…...
基于Spring Boot与Vue的智能房产匹配平台+文档
博主介绍:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐:最热的500个选题…...
【VMware】VMware 开启的虚拟机无法联网的解决方案
目录 🌊1. 问题说明 🌊2. 解决方案 🌍2.1 查看虚拟网络编辑器 🌍2.2 设置 vmnet 🌍2.3 设置虚拟机网络 🌍2.4 Xshell连接虚拟机 🌊1. 问题说明 虚拟机 ping 其他网页显示失败,比如&#…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
