前言

本指南以实际项目开发为主线,从选题策略、技术选型到实施细节,系统地解析毕业设计的全流程。我们不仅关注如何“完成”一个项目,更着眼于如何“做好”一个项目——如何在有限的时间内选择恰当的技术栈,如何设计可扩展的系统架构,如何在编码实践中培养工程思维,以及如何在论文撰写中清晰地表达技术见解。如果有在完成毕设的过程中遇见困难的同学,可以点击文章末尾的名片进行咨询,可免费送源码。

一、技术选型建议

后端:SpringBoot + MyBatis + MySQL
前端:Vue3 + Element Plus + Axios
部署:Nginx + 宝塔面板(简单易用)

选择理由:技术成熟、文档丰富、社区活跃,遇到问题容易找到解决方案。

二、项目核心架构

基础项目结构

src/main/java/com/项目名/
├── controller/    # 控制器
├── service/       # 业务层
├── mapper/        # 数据访问
├── entity/        # 实体类
├── dto/           # 数据传输对象
└── Application.java

关键配置

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_db
    username: root
    password: 123456
  servlet:
    multipart:
      max-file-size: 10MB

三、核心代码实现

1. 统一返回格式

@Data
public class Result<T> {
    private int code;      // 200成功,500失败
    private String msg;
    private T data;
    
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMsg("成功");
        result.setData(data);
        return result;
    }
}

2. 用户登录功能

@RestController
@RequestMapping("/user")
public class UserController {
    
    @PostMapping("/login")
    public Result<String> login(@RequestBody LoginDTO dto) {
        // 1. 验证用户名密码
        User user = userService.findByUsername(dto.getUsername());
        if(user == null || !user.getPassword().equals(dto.getPassword())) {
            return Result.error("用户名或密码错误");
        }
        
        // 2. 生成token
        String token = TokenUtil.createToken(user.getId());
        
        // 3. 返回结果
        return Result.success(token);
    }
}

3. 数据分页查询

@Service
public class UserService {
    
    public PageResult<User> getUsers(int page, int size) {
        PageHelper.startPage(page, size);  // MyBatis分页
        List<User> users = userMapper.selectAll();
        
        PageResult<User> result = new PageResult<>();
        result.setList(users);
        result.setTotal(((Page) users).getTotal());
        return result;
    }
}

4. 文件上传

@PostMapping("/upload")
public Result<String> upload(@RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        return Result.error("文件不能为空");
    }
    
    // 保存文件
    String fileName = UUID.randomUUID() + getExtension(file);
    String filePath = "uploads/" + fileName;
    
    file.transferTo(new File(filePath));
    
    return Result.success("/files/" + fileName);
}

四、数据库操作

基础CRUD示例

// Mapper接口
@Mapper
public interface UserMapper {
    @Insert("INSERT INTO user(username,password) VALUES(#{username},#{password})")
    int insert(User user);
    
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectById(Long id);
    
    @Update("UPDATE user SET username=#{username} WHERE id=#{id}")
    int update(User user);
    
    @Delete("DELETE FROM user WHERE id = #{id}")
    int delete(Long id);
}

分页查询优化

-- 添加索引提升查询效率
CREATE INDEX idx_username ON user(username);
CREATE INDEX idx_create_time ON user(create_time);

五、前端Vue开发

页面组件示例

<template>
  <div>
    <!-- 搜索框 -->
    <el-input v-model="searchKey" placeholder="搜索..." />
    
    <!-- 数据表格 -->
    <el-table :data="tableData">
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column label="操作">
        <template #default="scope">
          <el-button @click="edit(scope.row)">编辑</el-button>
          <el-button @click="del(scope.row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 分页 -->
    <el-pagination 
      @current-change="changePage"
      :current-page="currentPage"
      :page-size="pageSize"
      :total="total" />
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const tableData = ref([])
const currentPage = ref(1)
const total = ref(0)

// 加载数据
const loadData = async () => {
  const res = await axios.get('/api/data', {
    params: { page: currentPage.value }
  })
  tableData.value = res.data.list
  total.value = res.data.total
}

onMounted(() => {
  loadData()
})
</script>

API统一管理

// api/user.js
import request from '@/utils/request'

export const login = (data) => {
  return request.post('/user/login', data)
}

export const getUserList = (params) => {
  return request.get('/user/list', { params })
}

六、常见问题解决

1. 跨域问题

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");  // 允许所有域名
        config.addAllowedMethod("*");  // 允许所有方法
        config.addAllowedHeader("*");  // 允许所有头
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

2. 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<String> handleException(Exception e) {
        log.error("系统异常", e);
        return Result.error("系统异常:" + e.getMessage());
    }
}

3. 接口文档生成

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.yourpackage.controller"))
            .paths(PathSelectors.any())
            .build();
    }
}

七、部署上线

简单部署方式

  1. 打包:mvn clean package

  2. 上传:将jar包传到服务器

  3. 运行:java -jar your-app.jar

  4. 访问:http://服务器IP:8080

使用Nginx代理

server {
    listen 80;
    server_name localhost;
    
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

八、开发建议

  1. 先完成再完美:先实现核心功能,再优化细节

  2. 每天提交代码:使用Git管理版本

  3. 及时测试:每完成一个功能就测试

  4. 写好注释:关键代码要有注释说明

  5. 备份数据:定期备份数据库

核心提示:毕设程序的关键是实现核心功能并能正常运行。代码不必追求完美,但要保证稳定可用。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐