基于Vue3+Spring Boot创建一个个人博客项目 – 朝汐の小站
基于Vue3+Spring Boot创建一个个人博客项目
本文最后更新于 303 天前,如有错误请邮件至 zhiligyi222na@gmail.com

一、安装需要的环境

下载并安装npm

npm -v

使用create-vue脚手架来初始化Vue 3项目

npm create vue@latest .

选择配置

安装项目依赖

npm install

Vue前端项目已经准备就绪,现在让我们创建Spring Boot后端项目。我们将使用Spring Initializr来初始化项目

powershell -Command Invoke-WebRequest -Uri 'https://start.spring.io/starter.zip?type=maven-project&language=java&platformVersion=3.3.2&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=blog-backend&name=blog-backend&description=Blog%20Backend%20with%20Spring%20Boot&packageName=com.example.blog&dependencies=web,data-jpa,mysql,security,lombok' -OutFile blog-backend.zip

解压

powershell -Command Expand-Archive -Path blog-backend.zip -DestinationPath .\blog-backend
powershell -Command Expand-Archive -Path blog-backend.zip -DestinationPath ./blog-backend -Force

打开application.properties配置项

# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/blog_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

# 服务器配置
server.port=8080

# 允许跨域
spring.mvc.cors.allowed-origins=http://localhost:5173
spring.mvc.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
spring.mvc.cors.allowed-headers=*

接下来,我们需要创建实体类、仓库接口、服务类和控制器类等组件。让我们先创建所需的包结构。

powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\model
powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\repository
powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\service
powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\controller
powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\config
powershell -Command mkdir -Path d:\code\MyBlog\blog-backend\src\main\java\com\example\blog\dto

所有必要的包结构都已创建完成。现在,让我们开始实现后端的核心功能。首先,我们需要创建博客文章的实体类。

创建blog-backend\src\main\java\com\example\blog\model\Post.java实体类,我们需要创建博客文章的实体类。

package com.example.blog.model;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

@Entity
@Table(name = "posts")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

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

    @Column(updatable = false)
    private LocalDateTime createdAt;

    private LocalDateTime updatedAt;

    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }

    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
}

创建blog-backend\src\main\java\com\example\blog\repository\PostRepository.java接口,用于数据库操作。

package com.example.blog.repository;

import com.example.blog.model.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
    // 按照创建时间降序获取所有文章
    List<Post> findAllByOrderByCreatedAtDesc();

    // 根据作者查找文章
    List<Post> findByAuthor(String author);

    // 根据标题模糊搜索
    List<Post> findByTitleContaining(String keyword);
}

创建blog-backend\src\main\java\com\example\blog\service\PostService.java类来实现业务逻辑。

package com.example.blog.service;

import com.example.blog.model.Post;
import com.example.blog.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class PostService {
    private final PostRepository postRepository;

    @Autowired
    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }

    // 获取所有文章
    public List<Post> getAllPosts() {
        return postRepository.findAllByOrderByCreatedAtDesc();
    }

    // 获取指定id的文章
    public Optional<Post> getPostById(Long id) {
        return postRepository.findById(id);
    }

    // 创建新文章
    public Post createPost(Post post) {
        return postRepository.save(post);
    }

    // 更新文章
    public Post updatePost(Long id, Post postDetails) {
        Optional<Post> post = postRepository.findById(id);
        if (post.isPresent()) {
            Post updatedPost = post.get();
            updatedPost.setTitle(postDetails.getTitle());
            updatedPost.setContent(postDetails.getContent());
            updatedPost.setAuthor(postDetails.getAuthor());
            return postRepository.save(updatedPost);
        } else {
            throw new RuntimeException("Post not found with id: " + id);
        }
    }

    // 删除文章
    public void deletePost(Long id) {
        postRepository.deleteById(id);
    }

    // 根据作者查找文章
    public List<Post> getPostsByAuthor(String author) {
        return postRepository.findByAuthor(author);
    }

    // 根据标题搜索文章
    public List<Post> searchPostsByTitle(String keyword) {
        return postRepository.findByTitleContaining(keyword);
    }
}

创建blog-backend\src\main\java\com\example\blog\controller\PostController.java类来处理HTTP请求,提供RESTful API接口。

package com.example.blog.controller;

import com.example.blog.model.Post;
import com.example.blog.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/posts")
public class PostController {
    private final PostService postService;

    @Autowired
    public PostController(PostService postService) {
        this.postService = postService;
    }

    // 获取所有文章
    @GetMapping
    public ResponseEntity<List<Post>> getAllPosts() {
        List<Post> posts = postService.getAllPosts();
        return new ResponseEntity<>(posts, HttpStatus.OK);
    }

    // 获取指定id的文章
    @GetMapping("/{id}")
    public ResponseEntity<Post> getPostById(@PathVariable Long id) {
        Optional<Post> post = postService.getPostById(id);
        return post.map(value -> new ResponseEntity<>(value, HttpStatus.OK))
                .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    // 创建新文章
    @PostMapping
    public ResponseEntity<Post> createPost(@RequestBody Post post) {
        Post createdPost = postService.createPost(post);
        return new ResponseEntity<>(createdPost, HttpStatus.CREATED);
    }

    // 更新文章
    @PutMapping("/{id}")
    public ResponseEntity<Post> updatePost(@PathVariable Long id, @RequestBody Post postDetails) {
        try {
            Post updatedPost = postService.updatePost(id, postDetails);
            return new ResponseEntity<>(updatedPost, HttpStatus.OK);
        } catch (RuntimeException e) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }

    // 删除文章
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deletePost(@PathVariable Long id) {
        postService.deletePost(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    // 根据作者查找文章
    @GetMapping("/author/{author}")
    public ResponseEntity<List<Post>> getPostsByAuthor(@PathVariable String author) {
        List<Post> posts = postService.getPostsByAuthor(author);
        return new ResponseEntity<>(posts, HttpStatus.OK);
    }

    // 根据标题搜索文章
    @GetMapping("/search")
    public ResponseEntity<List<Post>> searchPostsByTitle(@RequestParam String keyword) {
        List<Post> posts = postService.searchPostsByTitle(keyword);
        return new ResponseEntity<>(posts, HttpStatus.OK);
    }
}

后端的核心功能类已经创建完成。接下来,我们需要配置Spring Security,以确保API的安全性。让我们创建一个blog-backend\src\main\java\com\example\blog\config\SecurityConfig.java类。

package com.example.blog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/posts/**").permitAll()
                .anyRequest().authenticated()
            );
        return http.build();
    }
}

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇