java+vue去快速實現文檔共享編輯的示例

這里提供一種基于Java和Vue的快速實現文檔共享編輯的示例,使用的技術棧包括Spring Boot、Spring Data JPA、MySQL和Vue.js。具體步驟如下:

1. 創建Spring Boot項目

使用Spring Initializr創建一個基于Spring Boot的項目,同時添加JPA和MySQL依賴。

2. 創建數據庫表

在MySQL數據庫中創建一個名為document的表,包含以下字段:


CREATE TABLE document (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  content TEXT NOT NULL
);

3. 創建實體類和Repository

創建一個名為Document的實體類,并通過注解@javax.persistence.Entity將其映射到數據庫表document中。

在同一個包下創建一個名為DocumentRepository的接口,繼承自JpaRepository<Document, Integer>,用于對數據庫進行CRUD操作。

4. 創建REST API

在Spring Boot項目中創建一個名為DocumentController的RestController,實現以下幾個API:

  • 獲取所有文檔列表:GET /documents
  • 獲取指定ID的文檔:GET /documents/{id}
  • 創建新文檔:POST /documents
  • 更新指定ID的文檔:PUT /documents/{id}
  • 刪除指定ID的文檔:DELETE /documents/{id}

實現方式可以參考下面給出的代碼示例。

5. 創建Vue.js應用

創建一個基于Vue.js的前端應用,實現以下功能:

  • 顯示所有文檔列表,支持分頁和查詢
  • 點擊某個文檔條目,查看該文檔的詳細內容
  • 點擊“新建文檔”按鈕,創建新文檔
  • 點擊“編輯”按鈕,對指定文檔進行編輯
  • 點擊“刪除”按鈕,刪除指定文檔

實現方式可以參考下面給出的代碼示例。

6. 部署和啟動

將后端代碼打包為jar包,通過命令行或者部署工具將其部署到服務器上,并啟動應用。

將前端代碼打包為靜態資源,并將其部署到Web服務器上,如Apache、Nginx等。

代碼示例

這里提供一些Java和Vue.js的代碼示例,供參考。

Document.java


@Entity
@Table(name = "document")
public class Document {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String title;
    private String content;
    // getters/setters
}

DocumentRepository.java


public interface DocumentRepository extends JpaRepository<Document, Integer> {
    Page<Document> findAllByTitleContaining(String title, Pageable pageable);
}

DocumentController.java


@RestController
@RequestMapping("/api/documents")
public class DocumentController {
    @Autowired
    private DocumentRepository repository;
    @GetMapping
    public Page<Document> findAll(@RequestParam(defaultValue = "") String q, @PageableDefault Pageable pageable) {
        return repository.findAllByTitleContaining(q, pageable);
    }
    @GetMapping("/{id}")
    public Document findById(@PathVariable int id) {
        return repository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Document not found"));
    }
    @PostMapping
    public Document create(@RequestBody Document document) {
        return repository.save(document);
    }
    @PutMapping("/{id}")
    public Document update(@PathVariable int id, @RequestBody Document document) {
        document.setId(id);
        return repository.save(document);
    }
    @DeleteMapping("/{id}")
    public void delete(@PathVariable int id) {
        repository.deleteById(id);
    }
}

App.vue


<template>
  <div>
    <h1>Document Sharing</h1>
    <div>
      <input v-model="searchQuery" @keyup.enter="searchDocuments()" placeholder="Search...">
      <button @click="searchDocuments()">Search</button>
    </div>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Title</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(doc, index) in documents" :key="doc.id">
          <td>{{ doc.id }}</td>
          <td>{{ doc.title }}</td>
          <td>
            <button @click="editDocument(index)">Edit</button>
            <button @click="deleteDocument(index)">Delete</button>
          </td>
        </tr>
      </tbody>
    </table>
    <div>
      <button @click="createDocument()">New Document</button>
    </div>
    <div v-if="selectedDocument">
      <h2>{{ selectedDocument.title }}</h2>
      <textarea v-model="selectedDocument.content"></textarea>
      <div>
        <button @click="saveDocument()">Save</button>
        <button @click="cancelEditing()">Cancel</button>
      </div>
    </div>
    <div v-else>
      <p>No document is selected.</p>
    </div>
    <div>
      <button :disabled="!hasPreviousPage" @click="goToPreviousPage()">Previous</button>
      <button :disabled="!hasNextPage" @click="goToNextPage()">Next</button>
      <span>Page {{ currentPage }} of {{ totalPages }}</span>
    </div>
  </div>
</template>
<script>
import axios from 'axios'
export default {
  name: 'app',
  data() {
    return {
      documents: [],
      selectedDocument: null,
      searchQuery: '',
      currentPage: 0,
      totalPages: 0,
      hasPreviousPage: false,
      hasNextPage: false,
      pageSize: 5
    }
  },
  mounted() {
    this.loadDocuments()
  },
  methods: {
    loadDocuments() {
      axios.get(`/api/documents?page=${this.currentPage}&size=${this.pageSize}&q=${this.searchQuery}`)
        .then(response => {
          this.documents = response.data.content
          this.totalPages = response.data.totalPages
          this.hasPreviousPage = response.data.number > 0
          this.hasNextPage = response.data.number < response.data.totalPages - 1
        }).catch(error => {
          console.error(error)
        })
    },
    createDocument() {
      this.selectedDocument = {
        title: '',
        content: ''
      }
    },
    editDocument(index) {
      this.selectedDocument = Object.assign({}, this.documents[index])
    },
    deleteDocument(index) {
      const doc = this.documents[index]
      axios.delete(`/api/documents/${doc.id}`)
        .then(() => {
          this.documents.splice(index, 1)
        }).catch(error => {
          console.error(error)
        })
    },
    saveDocument() {
      if (this.selectedDocument.id) { // update
        axios.put(`/api/documents/${this.selectedDocument.id}`, this.selectedDocument)
          .then(response => {
            Object.assign(this.documents.find(doc => doc.id === response.data.id), response.data)
            this.selectedDocument = null
          }).catch(error => {
            console.error(error)
          })
      } else { // create
        axios.post('/api/documents', this.selectedDocument)
          .then(response => {
            this.documents.push(response.data)
            this.selectedDocument = null
          }).catch(error => {
            console.error(error)
          })
      }
    },
    cancelEditing() {
      this.selectedDocument = null
    },
    searchDocuments() {
      this.currentPage = 0
      this.loadDocuments()
    },
    goToPreviousPage() {
      this.currentPage--
      this.loadDocuments()
    },
    goToNextPage() {
      this.currentPage++
      this.loadDocuments()
    }
  }
}
</script>
主站蜘蛛池模板: 精品少妇一区二区三区在线| 久久婷婷色综合一区二区| 亚洲欧美成人一区二区三区| 国产精品女同一区二区| 久久免费视频一区| 男女久久久国产一区二区三区| 久久久精品人妻一区二区三区| 91久久精品无码一区二区毛片| 性色AV一区二区三区无码| 精品一区二区三区在线视频观看| 久久国产精品一区| 亚洲一区在线免费观看| 波多野结衣一区在线观看| 国产亚洲自拍一区| 亚洲视频一区网站| 国产MD视频一区二区三区| 亚洲AV无码一区东京热| 国精产品999一区二区三区有限| 免费视频精品一区二区| 久久精品岛国av一区二区无码| 日韩成人无码一区二区三区| 亚洲国产一区明星换脸| 精品少妇ay一区二区三区| 日韩社区一区二区三区| 久久久久无码国产精品一区 | 搜日本一区二区三区免费高清视频 | 亚洲乱码国产一区三区| 亚洲午夜一区二区三区| www亚洲精品少妇裸乳一区二区 | 亚洲AV成人精品一区二区三区| 国产婷婷一区二区三区| 亚洲av成人一区二区三区观看在线 | 一本大道东京热无码一区| 亚洲一本一道一区二区三区| 在线观看精品视频一区二区三区| 搜日本一区二区三区免费高清视频| 亚洲综合一区二区精品导航| 国产伦精品一区二区三区免.费 | 中文字幕精品一区二区精品 | 国产成人一区二区三区精品久久| AV天堂午夜精品一区|