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 其他网页显示失败,比如&#…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
