{"id":1867,"date":"2025-02-04T17:12:05","date_gmt":"2025-02-04T09:12:05","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=1867"},"modified":"2025-02-04T17:12:05","modified_gmt":"2025-02-04T09:12:05","slug":"%e6%9c%80%e6%99%ae%e9%80%9a%e7%9a%84-cruds-%e8%83%bd10%e5%88%86%e9%92%9f%e5%bf%ab%e9%80%9f%e6%90%9e%e5%ae%9a%e5%90%97","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=1867","title":{"rendered":"\u6700\u666e\u901a\u7684 CRUDS \u80fd10\u5206\u949f\u5feb\u901f\u641e\u5b9a\u5417"},"content":{"rendered":"<h2>1. \u9879\u76ee\u7ed3\u6784<\/h2>\n<p>\u6211\u4eec\u5c06\u9879\u76ee\u5206\u4e3a\u4e24\u4e2a\u90e8\u5206\uff1a<\/p>\n<ul>\n<li><strong>\u540e\u7aef<\/strong>\uff1aSpring Boot + Spring Data JPA + MySQL<\/li>\n<li><strong>\u524d\u7aef<\/strong>\uff1aVue.js 3<\/li>\n<\/ul>\n<p>\u9879\u76ee\u7ed3\u6784\u5982\u4e0b\uff1a<\/p>\n<pre><code>task-manager\/\n\u251c\u2500\u2500 backend\/               # Spring Boot \u9879\u76ee\n\u2502   \u251c\u2500\u2500 src\/\n\u2502   \u2502   \u251c\u2500\u2500 main\/\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 java\/\n\u2502   \u2502   \u2502   \u2502   \u2514\u2500\u2500 com\/\n\u2502   \u2502   \u2502   \u2502       \u2514\u2500\u2500 example\/\n\u2502   \u2502   \u2502   \u2502           \u251c\u2500\u2500 controller\/\n\u2502   \u2502   \u2502   \u2502           \u251c\u2500\u2500 model\/\n\u2502   \u2502   \u2502   \u2502           \u251c\u2500\u2500 repository\/\n\u2502   \u2502   \u2502   \u2502           \u2514\u2500\u2500 service\/\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 resources\/\n\u2502   \u2502   \u2502       \u251c\u2500\u2500 application.properties\n\u2502   \u2502   \u2502       \u2514\u2500\u2500 data.sql\n\u2502   \u2502   \u2514\u2500\u2500 test\/\n\u2502   \u2514\u2500\u2500 pom.xml\n\u2514\u2500\u2500 frontend\/              # Vue.js 3 \u9879\u76ee\n    \u251c\u2500\u2500 public\/\n    \u251c\u2500\u2500 src\/\n    \u2502   \u251c\u2500\u2500 assets\/\n    \u2502   \u251c\u2500\u2500 components\/\n    \u2502   \u251c\u2500\u2500 router\/\n    \u2502   \u251c\u2500\u2500 views\/\n    \u2502   \u251c\u2500\u2500 App.vue\n    \u2502   \u2514\u2500\u2500 main.js\n    \u251c\u2500\u2500 package.json\n    \u2514\u2500\u2500 vite.config.js<\/code><\/pre>\n<hr \/>\n<h2>2. \u540e\u7aef\u5b9e\u73b0\uff08Spring Boot + Spring Data JPA + MySQL\uff09<\/h2>\n<h3>2.1 \u914d\u7f6e MySQL \u6570\u636e\u5e93<\/h3>\n<p>\u5728 <code>application.properties<\/code> \u4e2d\u914d\u7f6e MySQL \u8fde\u63a5\uff1a<\/p>\n<pre><code class=\"language-properties\">spring.datasource.url=jdbc:mysql:\/\/localhost:3306\/task_manager\nspring.datasource.username=root\nspring.datasource.password=yourpassword\nspring.jpa.hibernate.ddl-auto=update\nspring.jpa.show-sql=true<\/code><\/pre>\n<h3>2.2 \u521b\u5efa Task \u5b9e\u4f53\u7c7b<\/h3>\n<p>\u5728 <code>model<\/code> \u5305\u4e2d\u521b\u5efa <code>Task.java<\/code>\uff1a<\/p>\n<pre><code class=\"language-java\">package com.example.model;\n\nimport jakarta.persistence.*;\nimport java.time.LocalDateTime;\n\n@Entity\npublic class Task {\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    private String name;\n    private String priority;\n    private int duration; \/\/ in minutes\n    private LocalDateTime scheduleTime;\n    private LocalDateTime startTime;\n    private LocalDateTime endTime;\n    private LocalDateTime deadline;\n\n    \/\/ Getters and Setters\n    public Long getId() { return id; }\n    public void setId(Long id) { this.id = id; }\n    public String getName() { return name; }\n    public void setName(String name) { this.name = name; }\n    public String getPriority() { return priority; }\n    public void setPriority(String priority) { this.priority = priority; }\n    public int getDuration() { return duration; }\n    public void setDuration(int duration) { this.duration = duration; }\n    public LocalDateTime getScheduleTime() { return scheduleTime; }\n    public void setScheduleTime(LocalDateTime scheduleTime) { this.scheduleTime = scheduleTime; }\n    public LocalDateTime getStartTime() { return startTime; }\n    public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }\n    public LocalDateTime getEndTime() { return endTime; }\n    public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }\n    public LocalDateTime getDeadline() { return deadline; }\n    public void setDeadline(LocalDateTime deadline) { this.deadline = deadline; }\n}<\/code><\/pre>\n<h3>2.3 \u521b\u5efa TaskRepository \u63a5\u53e3<\/h3>\n<p>\u5728 <code>repository<\/code> \u5305\u4e2d\u521b\u5efa <code>TaskRepository.java<\/code>\uff1a<\/p>\n<pre><code class=\"language-java\">package com.example.repository;\n\nimport com.example.model.Task;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport java.util.List;\n\npublic interface TaskRepository extends JpaRepository&lt;Task, Long&gt; {\n    List&lt;Task&gt; findByNameContaining(String name); \/\/ \u641c\u7d22\u529f\u80fd\n}<\/code><\/pre>\n<h3>2.4 \u521b\u5efa TaskService \u670d\u52a1\u7c7b<\/h3>\n<p>\u5728 <code>service<\/code> \u5305\u4e2d\u521b\u5efa <code>TaskService.java<\/code>\uff1a<\/p>\n<pre><code class=\"language-java\">package com.example.service;\n\nimport com.example.model.Task;\nimport com.example.repository.TaskRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport java.util.List;\n\n@Service\npublic class TaskService {\n    @Autowired\n    private TaskRepository taskRepository;\n\n    public List&lt;Task&gt; getAllTasks() {\n        return taskRepository.findAll();\n    }\n\n    public Task getTaskById(Long id) {\n        return taskRepository.findById(id).orElse(null);\n    }\n\n    public Task createTask(Task task) {\n        return taskRepository.save(task);\n    }\n\n    public Task updateTask(Long id, Task taskDetails) {\n        Task task = taskRepository.findById(id).orElse(null);\n        if (task != null) {\n            task.setName(taskDetails.getName());\n            task.setPriority(taskDetails.getPriority());\n            task.setDuration(taskDetails.getDuration());\n            task.setScheduleTime(taskDetails.getScheduleTime());\n            task.setStartTime(taskDetails.getStartTime());\n            task.setEndTime(taskDetails.getEndTime());\n            task.setDeadline(taskDetails.getDeadline());\n            return taskRepository.save(task);\n        }\n        return null;\n    }\n\n    public void deleteTask(Long id) {\n        taskRepository.deleteById(id);\n    }\n\n    public List&lt;Task&gt; searchTasks(String name) {\n        return taskRepository.findByNameContaining(name);\n    }\n}<\/code><\/pre>\n<h3>2.5 \u521b\u5efa TaskController \u63a7\u5236\u5668<\/h3>\n<p>\u5728 <code>controller<\/code> \u5305\u4e2d\u521b\u5efa <code>TaskController.java<\/code>\uff1a<\/p>\n<pre><code class=\"language-java\">package com.example.controller;\n\nimport com.example.model.Task;\nimport com.example.service.TaskService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n@RestController\n@RequestMapping(&quot;\/api\/tasks&quot;)\npublic class TaskController {\n    @Autowired\n    private TaskService taskService;\n\n    @GetMapping\n    public List&lt;Task&gt; getAllTasks() {\n        return taskService.getAllTasks();\n    }\n\n    @GetMapping(&quot;\/{id}&quot;)\n    public Task getTaskById(@PathVariable Long id) {\n        return taskService.getTaskById(id);\n    }\n\n    @PostMapping\n    public Task createTask(@RequestBody Task task) {\n        return taskService.createTask(task);\n    }\n\n    @PutMapping(&quot;\/{id}&quot;)\n    public Task updateTask(@PathVariable Long id, @RequestBody Task taskDetails) {\n        return taskService.updateTask(id, taskDetails);\n    }\n\n    @DeleteMapping(&quot;\/{id}&quot;)\n    public void deleteTask(@PathVariable Long id) {\n        taskService.deleteTask(id);\n    }\n\n    @GetMapping(&quot;\/search&quot;)\n    public List&lt;Task&gt; searchTasks(@RequestParam String name) {\n        return taskService.searchTasks(name);\n    }\n}<\/code><\/pre>\n<hr \/>\n<h2>3. \u524d\u7aef\u5b9e\u73b0\uff08Vue.js 3\uff09<\/h2>\n<h3>3.1 \u521b\u5efa Vue.js \u9879\u76ee<\/h3>\n<p>\u4f7f\u7528 Vite \u521b\u5efa Vue.js \u9879\u76ee\uff1a<\/p>\n<pre><code class=\"language-bash\">npm create vite@latest frontend --template vue\ncd frontend\nnpm install<\/code><\/pre>\n<h3>3.2 \u5b89\u88c5 Axios<\/h3>\n<p>\u5b89\u88c5 Axios \u7528\u4e8e HTTP \u8bf7\u6c42\uff1a<\/p>\n<pre><code class=\"language-bash\">npm install axios<\/code><\/pre>\n<h3>3.3 \u521b\u5efa Task \u7ec4\u4ef6<\/h3>\n<p>\u5728 <code>src\/components\/<\/code> \u4e0b\u521b\u5efa <code>TaskList.vue<\/code> \u548c <code>TaskForm.vue<\/code>\u3002<\/p>\n<h4>TaskList.vue<\/h4>\n<pre><code class=\"language-vue\">&lt;template&gt;\n  &lt;div&gt;\n    &lt;h1&gt;Task List&lt;\/h1&gt;\n    &lt;input v-model=&quot;searchQuery&quot; placeholder=&quot;Search tasks&quot; @input=&quot;searchTasks&quot; \/&gt;\n    &lt;ul&gt;\n      &lt;li v-for=&quot;task in tasks&quot; :key=&quot;task.id&quot;&gt;\n        {{ task.name }} - {{ task.priority }}\n        &lt;button @click=&quot;editTask(task)&quot;&gt;Edit&lt;\/button&gt;\n        &lt;button @click=&quot;deleteTask(task.id)&quot;&gt;Delete&lt;\/button&gt;\n      &lt;\/li&gt;\n    &lt;\/ul&gt;\n  &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport axios from &#039;axios&#039;;\n\nexport default {\n  data() {\n    return {\n      tasks: [],\n      searchQuery: &#039;&#039;\n    };\n  },\n  created() {\n    this.fetchTasks();\n  },\n  methods: {\n    fetchTasks() {\n      axios.get(&#039;http:\/\/localhost:8080\/api\/tasks&#039;).then(response =&gt; {\n        this.tasks = response.data;\n      });\n    },\n    searchTasks() {\n      axios.get(`http:\/\/localhost:8080\/api\/tasks\/search?name=${this.searchQuery}`).then(response =&gt; {\n        this.tasks = response.data;\n      });\n    },\n    editTask(task) {\n      this.$emit(&#039;edit-task&#039;, task);\n    },\n    deleteTask(id) {\n      axios.delete(`http:\/\/localhost:8080\/api\/tasks\/${id}`).then(() =&gt; {\n        this.fetchTasks();\n      });\n    }\n  }\n};\n&lt;\/script&gt;<\/code><\/pre>\n<h4>TaskForm.vue<\/h4>\n<pre><code class=\"language-vue\">&lt;template&gt;\n  &lt;div&gt;\n    &lt;h2&gt;{{ editMode ? &#039;Edit Task&#039; : &#039;Create Task&#039; }}&lt;\/h2&gt;\n    &lt;form @submit.prevent=&quot;submitForm&quot;&gt;\n      &lt;input v-model=&quot;task.name&quot; placeholder=&quot;Name&quot; required \/&gt;\n      &lt;input v-model=&quot;task.priority&quot; placeholder=&quot;Priority&quot; required \/&gt;\n      &lt;input v-model=&quot;task.duration&quot; type=&quot;number&quot; placeholder=&quot;Duration (minutes)&quot; required \/&gt;\n      &lt;input v-model=&quot;task.scheduleTime&quot; type=&quot;datetime-local&quot; placeholder=&quot;Schedule Time&quot; \/&gt;\n      &lt;input v-model=&quot;task.startTime&quot; type=&quot;datetime-local&quot; placeholder=&quot;Start Time&quot; \/&gt;\n      &lt;input v-model=&quot;task.endTime&quot; type=&quot;datetime-local&quot; placeholder=&quot;End Time&quot; \/&gt;\n      &lt;input v-model=&quot;task.deadline&quot; type=&quot;datetime-local&quot; placeholder=&quot;Deadline&quot; \/&gt;\n      &lt;button type=&quot;submit&quot;&gt;{{ editMode ? &#039;Update&#039; : &#039;Create&#039; }}&lt;\/button&gt;\n    &lt;\/form&gt;\n  &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport axios from &#039;axios&#039;;\n\nexport default {\n  props: {\n    taskToEdit: {\n      type: Object,\n      default: () =&gt; ({})\n    }\n  },\n  data() {\n    return {\n      task: { ...this.taskToEdit },\n      editMode: !!this.taskToEdit.id\n    };\n  },\n  methods: {\n    submitForm() {\n      if (this.editMode) {\n        axios.put(`http:\/\/localhost:8080\/api\/tasks\/${this.task.id}`, this.task).then(() =&gt; {\n          this.$emit(&#039;task-updated&#039;);\n        });\n      } else {\n        axios.post(&#039;http:\/\/localhost:8080\/api\/tasks&#039;, this.task).then(() =&gt; {\n          this.$emit(&#039;task-created&#039;);\n        });\n      }\n    }\n  }\n};\n&lt;\/script&gt;<\/code><\/pre>\n<h3>3.4 \u5728 App.vue \u4e2d\u4f7f\u7528\u7ec4\u4ef6<\/h3>\n<pre><code class=\"language-vue\">&lt;template&gt;\n  &lt;div&gt;\n    &lt;TaskForm :taskToEdit=&quot;taskToEdit&quot; @task-created=&quot;fetchTasks&quot; @task-updated=&quot;fetchTasks&quot; \/&gt;\n    &lt;TaskList @edit-task=&quot;setTaskToEdit&quot; \/&gt;\n  &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport TaskForm from &#039;.\/components\/TaskForm.vue&#039;;\nimport TaskList from &#039;.\/components\/TaskList.vue&#039;;\n\nexport default {\n  components: {\n    TaskForm,\n    TaskList\n  },\n  data() {\n    return {\n      taskToEdit: {}\n    };\n  },\n  methods: {\n    fetchTasks() {\n      this.$refs.taskList.fetchTasks();\n    },\n    setTaskToEdit(task) {\n      this.taskToEdit = task;\n    }\n  }\n};\n&lt;\/script&gt;<\/code><\/pre>\n<hr \/>\n<h2>4. \u8fd0\u884c\u9879\u76ee<\/h2>\n<ol>\n<li>\u542f\u52a8 Spring Boot \u540e\u7aef\uff1a\n<pre><code class=\"language-bash\">cd backend\nmvn spring-boot:run<\/code><\/pre>\n<\/li>\n<li>\u542f\u52a8 Vue.js \u524d\u7aef\uff1a\n<pre><code class=\"language-bash\">cd frontend\nnpm run dev<\/code><\/pre>\n<\/li>\n<li>\u8bbf\u95ee <code>http:\/\/localhost:5173<\/code> \u5373\u53ef\u4f7f\u7528 Task \u7ba1\u7406\u529f\u80fd\u3002<\/li>\n<\/ol>\n<hr \/>\n<p>\u901a\u8fc7\u4ee5\u4e0a\u6b65\u9aa4\uff0c\u6211\u4eec\u5feb\u901f\u5b9e\u73b0\u4e86\u4e00\u4e2a\u57fa\u4e8e Spring Boot + Vue.js \u7684 Task CRUDS \u5e94\u7528\uff01<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. \u9879\u76ee\u7ed3\u6784 \u6211\u4eec\u5c06\u9879\u76ee\u5206\u4e3a\u4e24\u4e2a\u90e8\u5206\uff1a \u540e\u7aef\uff1aSpring Boot + Spring Data JPA + MySQL \u524d\u7aef\uff1aVue.js 3 \u9879\u76ee\u7ed3\u6784\u5982\u4e0b\uff1a task-manager\/ \u251c\u2500\u2500 backend\/ # Spring Boot \u9879\u76ee \u2502 \u251c\u2500\u2500 src\/ \u2502 \u2502 \u251c\u2500\u2500 main\/ \u2502 \u2502 \u2502 \u251c\u2500\u2500 java\/ \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500 com\/ \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500 example\/ \u2502 \u2502 \u2502 \u2502 \u251c\u2500\u2500 controller\/ \u2502 \u2502 \u2502 \u2502 [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=1867\" title=\"Permanent Link to: \u6700\u666e\u901a\u7684 CRUDS \u80fd10\u5206\u949f\u5feb\u901f\u641e\u5b9a\u5417\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-1867","post","type-post","status-publish","format-standard","hentry","category-5"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1867"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1867"}],"version-history":[{"count":1,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1867\/revisions"}],"predecessor-version":[{"id":1868,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1867\/revisions\/1868"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}