這里提供一種基于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>