1. 项目概述与技术栈选型
这个基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的宠物领养系统,是一个典型的全栈Web应用开发案例。作为从业多年的Java全栈开发者,我认为这个技术组合在当前企业级应用开发中具有很高的参考价值。
技术栈选择背后的考量:
- SpringBoot 2.x版本在企业中仍占据主流地位,相比最新的3.x版本,它的社区支持更成熟,遇到问题更容易找到解决方案
- Vue3作为前端框架,其Composition API提供了更好的代码组织方式,特别适合复杂交互的领养流程实现
- MyBatis-Plus在传统MyBatis基础上做了大量增强,可以节省约60%的常规CRUD代码量
- MySQL 8.0在JSON支持、窗口函数等方面的改进,非常适合存储宠物特征这类半结构化数据
提示:新手开发者常犯的错误是盲目追求最新版本。实际上,SpringBoot 2.7.x + Vue 3.2.x + MyBatis-Plus 3.5.x的组合在稳定性和功能完整性上已经足够优秀。
2. 系统架构设计与模块划分
2.1 后端工程结构
标准的Maven多模块结构如下:
pet-adoption ├── pet-common // 公共模块 ├── pet-system // 系统模块 ├── pet-admin // 管理后台API ├── pet-api // 用户端API └── pet-mobile // 移动端适配层关键配置点:
- 在application.yml中需要特别配置MySQL 8.0的连接参数:
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/pet_adoption?useSSL=false&serverTimezone=Asia/Shanghai username: root password: 你的密码- MyBatis-Plus的分页插件配置:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }2.2 前端工程结构
Vue3项目采用典型的Vite工程结构:
src/ ├── api/ // 接口定义 ├── assets/ // 静态资源 ├── components/ // 公共组件 ├── router/ // 路由配置 ├── stores/ // Pinia状态管理 ├── utils/ // 工具函数 └── views/ // 页面组件关键配置点:
- 在vite.config.js中需要配置代理解决跨域:
server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '') } } }3. 核心功能实现细节
3.1 宠物信息管理模块
后端实体类设计示例:
@Data @TableName("pet_info") public class PetInfo { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String gender; private String type; // 猫/狗等 private String healthStatus; private String description; @TableField(typeHandler = JacksonTypeHandler.class) private List<String> images; // 使用JSON存储图片列表 private LocalDateTime createTime; }前端使用Element Plus实现表单:
<template> <el-form :model="form" label-width="120px"> <el-form-item label="宠物名称"> <el-input v-model="form.name" /> </el-form-item> <el-form-item label="年龄"> <el-input-number v-model="form.age" :min="0" /> </el-form-item> <el-form-item label="性别"> <el-radio-group v-model="form.gender"> <el-radio-button label="male">雄性</el-radio-button> <el-radio-button label="female">雌性</el-radio-button> </el-radio-group> </el-form-item> <!-- 其他表单项 --> </el-form> </template>3.2 领养申请流程
状态机设计:
public enum AdoptionStatus { PENDING_REVIEW, // 待审核 APPROVED, // 审核通过 REJECTED, // 审核拒绝 COMPLETED // 领养完成 }业务逻辑实现:
@Service @RequiredArgsConstructor public class AdoptionServiceImpl implements AdoptionService { private final AdoptionMapper adoptionMapper; @Transactional public void processAdoption(Long adoptionId, AdoptionStatus status) { Adoption adoption = adoptionMapper.selectById(adoptionId); if (adoption == null) { throw new BusinessException("领养记录不存在"); } // 状态校验 if (adoption.getStatus() != AdoptionStatus.PENDING_REVIEW) { throw new BusinessException("当前状态不允许此操作"); } adoption.setStatus(status); adoption.setReviewTime(LocalDateTime.now()); adoptionMapper.updateById(adoption); // 如果审核通过,更新宠物状态 if (status == AdoptionStatus.APPROVED) { petService.updatePetStatus(adoption.getPetId(), PetStatus.ADOPTED); } } }4. 开发中的典型问题与解决方案
4.1 MyBatis-Plus版本兼容性问题
常见报错:"java: You aren't using a compiler supported by lombok..."
解决方案:
- 确保Lombok版本与JDK版本匹配
- 在IDEA中启用注解处理:
- Settings → Build → Compiler → Annotation Processors
- 勾选"Enable annotation processing"
4.2 Vue3组件通信问题
在宠物详情页和领养表单组件间共享数据的最佳实践:
// 使用Pinia状态管理 import { defineStore } from 'pinia' export const usePetStore = defineStore('pet', { state: () => ({ currentPet: null }), actions: { setCurrentPet(pet) { this.currentPet = pet } } }) // 在组件中使用 const petStore = usePetStore() petStore.setCurrentPet(selectedPet)4.3 文件上传实现
后端接收多文件上传:
@PostMapping("/upload") public Result<List<String>> uploadFiles(@RequestParam("files") MultipartFile[] files) { List<String> urls = new ArrayList<>(); for (MultipartFile file : files) { String url = ossService.upload(file); urls.add(url); } return Result.success(urls); }前端实现拖拽上传:
<template> <el-upload action="/api/upload" multiple drag :on-success="handleSuccess" > <i class="el-icon-upload"></i> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> </el-upload> </template>5. 性能优化实践
5.1 数据库优化
针对宠物列表查询的优化方案:
-- 创建合适的索引 CREATE INDEX idx_pet_type ON pet_info(type); CREATE INDEX idx_pet_status ON pet_info(status); -- 使用覆盖索引优化查询 EXPLAIN SELECT id, name, age FROM pet_info WHERE type = 'DOG' AND status = 'AVAILABLE';5.2 缓存策略
使用Spring Cache实现缓存:
@Cacheable(value = "pet", key = "#id") public PetInfo getPetById(Long id) { return petMapper.selectById(id); } @CacheEvict(value = "pet", key = "#pet.id") public void updatePet(PetInfo pet) { petMapper.updateById(pet); }5.3 前端性能优化
- 组件懒加载:
const PetDetail = () => import('./views/PetDetail.vue')- API请求防抖:
import { debounce } from 'lodash-es' const searchPets = debounce(async (keyword) => { const res = await api.searchPets(keyword) petList.value = res.data }, 500)6. 安全防护措施
6.1 认证与授权
JWT实现方案:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }6.2 SQL注入防护
MyBatis-Plus已经内置了SQL注入防护,但需要注意:
- 永远不要直接拼接SQL语句
- 使用QueryWrapper时也要注意:
// 错误做法 wrapper.apply("date_format(create_time,'%Y-%m-%d') = '" + date + "'"); // 正确做法 wrapper.apply("date_format(create_time,'%Y-%m-%d') = {0}", date);6.3 XSS防护
前端使用DOMPurify净化输入:
import DOMPurify from 'dompurify' const clean = DOMPurify.sanitize(userInput)后端同时做校验:
@NotBlank @Size(max = 500) @Pattern(regexp = "^[a-zA-Z0-9\\u4e00-\\u9fa5,。、;:?!()【】「」“”‘’…—\-—~·]+$") private String description;7. 部署与监控
7.1 生产环境部署
推荐使用Docker Compose部署:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: pet@1234 MYSQL_DATABASE: pet_adoption ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql backend: build: ./backend ports: - "8080:8080" depends_on: - mysql frontend: build: ./frontend ports: - "80:80" depends_on: - backend volumes: mysql_data:7.2 监控配置
SpringBoot Actuator配置:
management: endpoints: web: exposure: include: health,info,metrics endpoint: health: show-details: always前端错误监控(Sentry示例):
import * as Sentry from '@sentry/vue' Sentry.init({ app, dsn: 'your-dsn', integrations: [ new Sentry.BrowserTracing({ routingInstrumentation: Sentry.vueRouterInstrumentation(router) }) ], tracesSampleRate: 0.2 })8. 项目文档编写要点
完善的文档应该包含:
- 本地开发环境搭建指南
- 数据库初始化脚本
- API接口文档(推荐使用Swagger或Knife4j)
- 前端组件说明
- 部署手册
- 常见问题解答
Swagger配置示例:
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.pet.adoption.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("宠物领养系统API文档") .description("前后端交互接口说明") .version("1.0") .build(); } }在实际开发中,我发现很多团队忽视了文档的重要性。一个好的文档应该像代码一样维护,建议将文档纳入版本控制系统,与代码同步更新。对于宠物领养系统这类涉及多方协作的项目,清晰的文档可以减少80%以上的沟通成本。