当前位置: 首页 > news >正文

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>
```

通过上述步骤,我们已经建立了一个功能完善的个人博客系统。这个系统包括用户注册和登录、文章的增删改查、评论和标签系统,以及富文本编辑器的支持。

http://www.lryc.cn/news/387214.html

相关文章:

  • 停车场智能化管理:车位引导系统实现车位资源优化与数据分析
  • 梯度下降法
  • 【高考志愿】光学工程
  • Golang | Leetcode Golang题解之第205题同构字符串
  • 【Unity】RPG2D龙城纷争(五)关卡编辑器之地图编辑
  • 音视频入门基础:H.264专题(4)——NALU Header:forbidden_zero_bit、nal_ref_idc、nal_unit_type简介
  • 基于深度学习的人脸关键点检测
  • C++自定义智能指针
  • 一个合理的前端应用文件结构
  • spring和springboot的关系是什么?
  • 智慧校园-医务管理系统总体概述
  • AUTOSAR汽车电子嵌入式编程精讲300篇-智能网联汽车CAN总线-基于电压信号的CAN总线入侵检测系统设计与实现
  • BLACKBOX.AI:解锁编程学习新纪元,加速开发的AI得力助手
  • 实验三 时序逻辑电路实验
  • 云计算基础技术
  • 【动态规划】2306. 公司命名
  • 熟练掌握爬虫技术
  • 基于Spring Boot与Vue的智能房产匹配平台+文档
  • 【VMware】VMware 开启的虚拟机无法联网的解决方案
  • linux——线程
  • install nebula with source
  • 拆分盘投资策略解析:机制、案例与风险考量
  • Redis主从复制、哨兵模式以及Cluster集群
  • 【chatgpt】npy文件和npz文件区别
  • 为什么IP地址会被列入黑名单?
  • 【OceanBase诊断调优】—— 如何查找表被哪些其它表引用外键
  • 网络编程常见问题
  • 回调函数的使用详解
  • <电力行业> - 《第8课:输电(一)》
  • 【python学习】 __pycache__ 文件是什么