{"id":1483,"date":"2025-08-22T20:11:03","date_gmt":"2025-08-22T12:11:03","guid":{"rendered":"https:\/\/zero-zl.cn\/?p=1483"},"modified":"2025-08-28T09:03:26","modified_gmt":"2025-08-28T01:03:26","slug":"%e5%9f%ba%e4%ba%8evue3spring-boot%e5%88%9b%e5%bb%ba%e4%b8%80%e4%b8%aa%e4%b8%aa%e4%ba%ba%e5%8d%9a%e5%ae%a2%e9%a1%b9%e7%9b%ae","status":"publish","type":"post","link":"https:\/\/zero-zl.cn\/index.php\/2025\/08\/22\/%e5%9f%ba%e4%ba%8evue3spring-boot%e5%88%9b%e5%bb%ba%e4%b8%80%e4%b8%aa%e4%b8%aa%e4%ba%ba%e5%8d%9a%e5%ae%a2%e9%a1%b9%e7%9b%ae\/","title":{"rendered":"\u57fa\u4e8eVue3+Spring Boot\u521b\u5efa\u4e00\u4e2a\u4e2a\u4eba\u535a\u5ba2\u9879\u76ee"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">\u4e00\u3001\u5b89\u88c5\u9700\u8981\u7684\u73af\u5883<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u4e0b\u8f7d\u5e76\u5b89\u88c5npm<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm -v<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u4f7f\u7528create-vue\u811a\u624b\u67b6\u6765\u521d\u59cb\u5316Vue 3\u9879\u76ee<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm create vue@latest .<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u9009\u62e9\u914d\u7f6e<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/zero-zl.cn\/wp-content\/uploads\/2025\/08\/image-33.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  loading=\"lazy\" decoding=\"async\" width=\"925\" height=\"515\" data-original=\"https:\/\/zero-zl.cn\/wp-content\/uploads\/2025\/08\/image-33.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" alt=\"\" class=\"wp-image-1485\" style=\"width:589px;height:auto\"  sizes=\"auto, (max-width: 925px) 100vw, 925px\" \/><\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u5b89\u88c5\u9879\u76ee\u4f9d\u8d56<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vue\u524d\u7aef\u9879\u76ee\u5df2\u7ecf\u51c6\u5907\u5c31\u7eea\uff0c\u73b0\u5728\u8ba9\u6211\u4eec\u521b\u5efaSpring Boot\u540e\u7aef\u9879\u76ee\u3002\u6211\u4eec\u5c06\u4f7f\u7528Spring Initializr\u6765\u521d\u59cb\u5316\u9879\u76ee<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command Invoke-WebRequest -Uri 'https:\/\/start.spring.io\/starter.zip?type=maven-project&amp;language=java&amp;platformVersion=3.3.2&amp;packaging=jar&amp;jvmVersion=17&amp;groupId=com.example&amp;artifactId=blog-backend&amp;name=blog-backend&amp;description=Blog%20Backend%20with%20Spring%20Boot&amp;packageName=com.example.blog&amp;dependencies=web,data-jpa,mysql,security,lombok' -OutFile blog-backend.zip<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u89e3\u538b<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command Expand-Archive -Path blog-backend.zip -DestinationPath .\\blog-backend<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command Expand-Archive -Path blog-backend.zip -DestinationPath .\/blog-backend -Force<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u6253\u5f00application.properties\u914d\u7f6e\u9879<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \u6570\u636e\u5e93\u914d\u7f6e\nspring.datasource.url=jdbc:mysql:\/\/localhost:3306\/blog_db?useSSL=false&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true\nspring.datasource.username=root\nspring.datasource.password=password\nspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver\n\n# JPA\u914d\u7f6e\nspring.jpa.hibernate.ddl-auto=update\nspring.jpa.show-sql=true\nspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect\n\n# \u670d\u52a1\u5668\u914d\u7f6e\nserver.port=8080\n\n# \u5141\u8bb8\u8de8\u57df\nspring.mvc.cors.allowed-origins=http:\/\/localhost:5173\nspring.mvc.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS\nspring.mvc.cors.allowed-headers=*<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u9700\u8981\u521b\u5efa\u5b9e\u4f53\u7c7b\u3001\u4ed3\u5e93\u63a5\u53e3\u3001\u670d\u52a1\u7c7b\u548c\u63a7\u5236\u5668\u7c7b\u7b49\u7ec4\u4ef6\u3002\u8ba9\u6211\u4eec\u5148\u521b\u5efa\u6240\u9700\u7684\u5305\u7ed3\u6784\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\model<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\repository<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\service<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\controller<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\config<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>powershell -Command mkdir -Path d:\\code\\MyBlog\\blog-backend\\src\\main\\java\\com\\example\\blog\\dto<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u6240\u6709\u5fc5\u8981\u7684\u5305\u7ed3\u6784\u90fd\u5df2\u521b\u5efa\u5b8c\u6210\u3002\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u5f00\u59cb\u5b9e\u73b0\u540e\u7aef\u7684\u6838\u5fc3\u529f\u80fd\u3002\u9996\u5148\uff0c\u6211\u4eec\u9700\u8981\u521b\u5efa\u535a\u5ba2\u6587\u7ae0\u7684\u5b9e\u4f53\u7c7b\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u521b\u5efablog-backend\\src\\main\\java\\com\\example\\blog\\model\\Post.java\u5b9e\u4f53\u7c7b\uff0c\u6211\u4eec\u9700\u8981\u521b\u5efa\u535a\u5ba2\u6587\u7ae0\u7684\u5b9e\u4f53\u7c7b\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.blog.model;\n\nimport jakarta.persistence.*;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport java.time.LocalDateTime;\n\n@Entity\n@Table(name = \"posts\")\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Post {\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    @Column(nullable = false, length = 255)\n    private String title;\n\n    @Column(nullable = false, columnDefinition = \"TEXT\")\n    private String content;\n\n    @Column(nullable = false, length = 100)\n    private String author;\n\n    @Column(updatable = false)\n    private LocalDateTime createdAt;\n\n    private LocalDateTime updatedAt;\n\n    @PrePersist\n    protected void onCreate() {\n        createdAt = LocalDateTime.now();\n        updatedAt = LocalDateTime.now();\n    }\n\n    @PreUpdate\n    protected void onUpdate() {\n        updatedAt = LocalDateTime.now();\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u521b\u5efablog-backend\\src\\main\\java\\com\\example\\blog\\repository\\PostRepository.java\u63a5\u53e3\uff0c\u7528\u4e8e\u6570\u636e\u5e93\u64cd\u4f5c\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.blog.repository;\n\nimport com.example.blog.model.Post;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface PostRepository extends JpaRepository&lt;Post, Long> {\n    \/\/ \u6309\u7167\u521b\u5efa\u65f6\u95f4\u964d\u5e8f\u83b7\u53d6\u6240\u6709\u6587\u7ae0\n    List&lt;Post> findAllByOrderByCreatedAtDesc();\n\n    \/\/ \u6839\u636e\u4f5c\u8005\u67e5\u627e\u6587\u7ae0\n    List&lt;Post> findByAuthor(String author);\n\n    \/\/ \u6839\u636e\u6807\u9898\u6a21\u7cca\u641c\u7d22\n    List&lt;Post> findByTitleContaining(String keyword);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u521b\u5efablog-backend\\src\\main\\java\\com\\example\\blog\\service\\PostService.java\u7c7b\u6765\u5b9e\u73b0\u4e1a\u52a1\u903b\u8f91\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.blog.service;\n\nimport com.example.blog.model.Post;\nimport com.example.blog.repository.PostRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Optional;\n\n@Service\npublic class PostService {\n    private final PostRepository postRepository;\n\n    @Autowired\n    public PostService(PostRepository postRepository) {\n        this.postRepository = postRepository;\n    }\n\n    \/\/ \u83b7\u53d6\u6240\u6709\u6587\u7ae0\n    public List&lt;Post> getAllPosts() {\n        return postRepository.findAllByOrderByCreatedAtDesc();\n    }\n\n    \/\/ \u83b7\u53d6\u6307\u5b9aid\u7684\u6587\u7ae0\n    public Optional&lt;Post> getPostById(Long id) {\n        return postRepository.findById(id);\n    }\n\n    \/\/ \u521b\u5efa\u65b0\u6587\u7ae0\n    public Post createPost(Post post) {\n        return postRepository.save(post);\n    }\n\n    \/\/ \u66f4\u65b0\u6587\u7ae0\n    public Post updatePost(Long id, Post postDetails) {\n        Optional&lt;Post> post = postRepository.findById(id);\n        if (post.isPresent()) {\n            Post updatedPost = post.get();\n            updatedPost.setTitle(postDetails.getTitle());\n            updatedPost.setContent(postDetails.getContent());\n            updatedPost.setAuthor(postDetails.getAuthor());\n            return postRepository.save(updatedPost);\n        } else {\n            throw new RuntimeException(\"Post not found with id: \" + id);\n        }\n    }\n\n    \/\/ \u5220\u9664\u6587\u7ae0\n    public void deletePost(Long id) {\n        postRepository.deleteById(id);\n    }\n\n    \/\/ \u6839\u636e\u4f5c\u8005\u67e5\u627e\u6587\u7ae0\n    public List&lt;Post> getPostsByAuthor(String author) {\n        return postRepository.findByAuthor(author);\n    }\n\n    \/\/ \u6839\u636e\u6807\u9898\u641c\u7d22\u6587\u7ae0\n    public List&lt;Post> searchPostsByTitle(String keyword) {\n        return postRepository.findByTitleContaining(keyword);\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u521b\u5efablog-backend\\src\\main\\java\\com\\example\\blog\\controller\\PostController.java\u7c7b\u6765\u5904\u7406HTTP\u8bf7\u6c42\uff0c\u63d0\u4f9bRESTful API\u63a5\u53e3\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.blog.controller;\n\nimport com.example.blog.model.Post;\nimport com.example.blog.service.PostService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Optional;\n\n@RestController\n@RequestMapping(\"\/api\/posts\")\npublic class PostController {\n    private final PostService postService;\n\n    @Autowired\n    public PostController(PostService postService) {\n        this.postService = postService;\n    }\n\n    \/\/ \u83b7\u53d6\u6240\u6709\u6587\u7ae0\n    @GetMapping\n    public ResponseEntity&lt;List&lt;Post>> getAllPosts() {\n        List&lt;Post> posts = postService.getAllPosts();\n        return new ResponseEntity&lt;>(posts, HttpStatus.OK);\n    }\n\n    \/\/ \u83b7\u53d6\u6307\u5b9aid\u7684\u6587\u7ae0\n    @GetMapping(\"\/{id}\")\n    public ResponseEntity&lt;Post> getPostById(@PathVariable Long id) {\n        Optional&lt;Post> post = postService.getPostById(id);\n        return post.map(value -> new ResponseEntity&lt;>(value, HttpStatus.OK))\n                .orElseGet(() -> new ResponseEntity&lt;>(HttpStatus.NOT_FOUND));\n    }\n\n    \/\/ \u521b\u5efa\u65b0\u6587\u7ae0\n    @PostMapping\n    public ResponseEntity&lt;Post> createPost(@RequestBody Post post) {\n        Post createdPost = postService.createPost(post);\n        return new ResponseEntity&lt;>(createdPost, HttpStatus.CREATED);\n    }\n\n    \/\/ \u66f4\u65b0\u6587\u7ae0\n    @PutMapping(\"\/{id}\")\n    public ResponseEntity&lt;Post> updatePost(@PathVariable Long id, @RequestBody Post postDetails) {\n        try {\n            Post updatedPost = postService.updatePost(id, postDetails);\n            return new ResponseEntity&lt;>(updatedPost, HttpStatus.OK);\n        } catch (RuntimeException e) {\n            return new ResponseEntity&lt;>(HttpStatus.NOT_FOUND);\n        }\n    }\n\n    \/\/ \u5220\u9664\u6587\u7ae0\n    @DeleteMapping(\"\/{id}\")\n    public ResponseEntity&lt;Void> deletePost(@PathVariable Long id) {\n        postService.deletePost(id);\n        return new ResponseEntity&lt;>(HttpStatus.NO_CONTENT);\n    }\n\n    \/\/ \u6839\u636e\u4f5c\u8005\u67e5\u627e\u6587\u7ae0\n    @GetMapping(\"\/author\/{author}\")\n    public ResponseEntity&lt;List&lt;Post>> getPostsByAuthor(@PathVariable String author) {\n        List&lt;Post> posts = postService.getPostsByAuthor(author);\n        return new ResponseEntity&lt;>(posts, HttpStatus.OK);\n    }\n\n    \/\/ \u6839\u636e\u6807\u9898\u641c\u7d22\u6587\u7ae0\n    @GetMapping(\"\/search\")\n    public ResponseEntity&lt;List&lt;Post>> searchPostsByTitle(@RequestParam String keyword) {\n        List&lt;Post> posts = postService.searchPostsByTitle(keyword);\n        return new ResponseEntity&lt;>(posts, HttpStatus.OK);\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u540e\u7aef\u7684\u6838\u5fc3\u529f\u80fd\u7c7b\u5df2\u7ecf\u521b\u5efa\u5b8c\u6210\u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u9700\u8981\u914d\u7f6eSpring Security\uff0c\u4ee5\u786e\u4fddAPI\u7684\u5b89\u5168\u6027\u3002\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2ablog-backend\\src\\main\\java\\com\\example\\blog\\config\\SecurityConfig.java\u7c7b\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.blog.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig {\n\n    @Bean\n    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {\n        http\n            .csrf(AbstractHttpConfigurer::disable)\n            .authorizeHttpRequests(auth -> auth\n                .requestMatchers(\"\/api\/posts\/**\").permitAll()\n                .anyRequest().authenticated()\n            );\n        return http.build();\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e00\u3001\u5b89\u88c5\u9700\u8981\u7684\u73af\u5883 \u4e0b\u8f7d\u5e76\u5b89\u88c5npm \u4f7f\u7528create-vue\u811a\u624b\u67b6\u6765\u521d\u59cb\u5316Vue 3\u9879\u76ee \u9009\u62e9\u914d\u7f6e \u5b89\u88c5\u9879\u76ee [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":113,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[102],"tags":[],"class_list":["post-1483","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-102"],"_links":{"self":[{"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/posts\/1483","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/comments?post=1483"}],"version-history":[{"count":2,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/posts\/1483\/revisions"}],"predecessor-version":[{"id":1487,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/posts\/1483\/revisions\/1487"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/media\/113"}],"wp:attachment":[{"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/media?parent=1483"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/categories?post=1483"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero-zl.cn\/index.php\/wp-json\/wp\/v2\/tags?post=1483"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}