Loading... # Java + Vue 实现 **通讯录列表**(后端 Spring Boot + 前端 Vue3,精炼实战)📇✨ 下面给出完整的 **后端接口、数据库建表、前端组件** 与工作流程图,代码可直接参考并在工程中落地。关键点以红色标注,重要解释紧跟代码段逐条说明。 --- ## 数据库(MySQL)建表 ```sql CREATE TABLE contacts ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, phone VARCHAR(30), email VARCHAR(100), address VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY(id), INDEX idx_name (name) ) ENGINE=InnoDB CHARSET=utf8mb4; ``` **解释**:创建 `contacts` 表;`id` 自增主键;`idx_name` 提速按姓名搜索;使用 `utf8mb4` 支持多语言/表情。 --- ## 后端(Spring Boot)关键代码 ### 实体 `Contact` ```java @Entity @Table(name="contacts") public class Contact { @Id @GeneratedValue private Long id; @Column(nullable=false) private String name; private String phone; private String email; private String address; // getters/setters } ``` **解释**:JPA 实体映射表 `contacts`,`@Column(nullable=false)` 强制 `name` 非空。 ### 仓库 `ContactRepository` ```java public interface ContactRepository extends JpaRepository<Contact, Long> { Page<Contact> findByNameContainingIgnoreCase(String name, Pageable page); } ``` **解释**:继承 `JpaRepository` 获得 CRUD;自定义按 `name` 模糊分页查询用于前端搜索与分页。 ### 服务与控制器(核心接口) ```java @RestController @RequestMapping("/api/contacts") @RequiredArgsConstructor public class ContactController { private final ContactRepository repo; @GetMapping public Page<Contact> list(@RequestParam(required=false) String q, @RequestParam(defaultValue="0") int page, @RequestParam(defaultValue="10") int size) { Pageable p = PageRequest.of(page, size, Sort.by("name")); return (q==null || q.isBlank()) ? repo.findAll(p) : repo.findByNameContainingIgnoreCase(q, p); } @PostMapping public Contact create(@RequestBody @Valid Contact c){ return repo.save(c); } @PutMapping("/{id}") public ResponseEntity<Contact> update(@PathVariable Long id, @RequestBody Contact c){ return repo.findById(id).map(ex -> { ex.setName(c.getName()); ex.setPhone(c.getPhone()); ex.setEmail(c.getEmail()); ex.setAddress(c.getAddress()); return ResponseEntity.ok(repo.save(ex)); }).orElse(ResponseEntity.notFound().build()); } @DeleteMapping("/{id}") public void delete(@PathVariable Long id){ repo.deleteById(id); } } ``` **解释**: * `GET /api/contacts?q=&page=&size=`:分页与可选模糊搜索。 * `POST`:新增联系人(请求体验证可加 `@Valid` + DTO)。 * `PUT/{id}`:更新;先查再改,避免盲写。 * `DELETE/{id}`:删除。 使用分页可避免一次返回大量数据,提升性能并便于前端分页显示。注意:生产需加异常处理与鉴权。 --- ## 构建与运行命令(后端) ```bash mvn clean package -DskipTests java -jar target/app.jar ``` **解释**:`mvn clean package` 打包 Spring Boot 应用;`-DskipTests` 跳过测试用于快速运行;`java -jar` 启动可执行 jar。 --- ## 前端(Vue3 + Composition API)关键片段 ### 安装依赖(命令) ```bash npm install vue@next axios ``` **解释**:安装 Vue3 与 axios(用于 HTTP 请求)。 ### 组件 `ContactList.vue` ```vue <template> <div> <input v-model="q" @input="fetch(0)" placeholder="搜索姓名" /> <button @click="openAdd">新增</button> <table> <tr v-for="c in contacts" :key="c.id"> <td><ruby>c.name}}</td><td>{{c.phone}}</td><td>{{c.email}}</td> <td><button @click="edit(c)">编辑</button><button @click="del(c.id)">删除</button></td> </tr> </table> <div> <button @click="fetch(page-1)"<rp> (</rp><rt>disabled="page===0">上一页</button> <span>第 {{page+1</rt><rp>) </rp></ruby> 页</span> <button @click="fetch(page+1)" :disabled="!hasNext">下一页</button> </div> <!-- Add/Edit modal omitted for brevity --> </div> </template> <script setup> import {ref} from 'vue'; import axios from 'axios'; const contacts = ref([]); const page = ref(0); const size = 10; const q = ref(''); const hasNext = ref(false); async function fetch(p=0){ if(p<0) return; const resp = await axios.get('/api/contacts', {params:{q: q.value, page: p, size}}); contacts.value = resp.data.content; page.value = resp.data.number; hasNext.value = !resp.data.last; } async function del(id){ if(!confirm('确认删除?')) return; await axios.delete(`/api/contacts/${id}`); fetch(page.value); } </script> ``` **解释**: * `fetch` 发 `GET` 请求并处理 `Page` 返回结构(Spring Data 默认分页 JSON)。 * `q` 为搜索关键字,实时触发第一页查询。 * 简单分页控制 `上一页/下一页`,并根据后端返回 `last` 字段判断是否还有下一页。 * 在生产中应加入 loading、错误提示与表单验证。 --- ## 设计对比表(分页方式) | 方案 | 优点 | 缺点 | | ------------------ | -------------------: | ---------------------------------- | | 偏移分页(OFFSET) | 实现简单,兼容性好 | 大数据集页偏移慢,重复/遗漏可能 | | 键集分页(Keyset) | 高效,稳定(无重复) | 需基于索引字段,不支持跳页任意访问 | **解释**:小到中型通讯录用偏移分页足够;海量数据推荐键集分页。 --- ## 工作流程(Mermaid) ```mermaid flowchart LR U[用户浏览器] -->|请求列表| B[Vue 前端 fetch] B -->|GET /api/contacts| S[Spring Boot 控制器] S --> R[ContactRepository 查询 MySQL] R --> S S -->|返回 Page JSON| B B --> U[渲染表格] ``` --- ### 小结(要点) * 先实现后端 **REST CRUD + 分页/搜索**,再做前端组件化渲染;分页与参数化查询是关键。🔑 * 注意安全(输入校验、鉴权、CORS)、性能(索引、分页策略)与用户体验(loading、确认框、表单校验)。😊 需要我把完整的前后端工程代码(含表单 modal、校验规则、CORS 配置与单元测试示例)整理成一个可下载工程结构并逐行注释吗? 最后修改:2025 年 09 月 05 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏