☰
Spring Boot+微信小程序:社区疫情报备系统从0到1实战
2026/10/15 4:49:01 网站建设 项目流程

最近好几个做毕设的同学都在问同一个问题:“Spring Boot + 小程序做社区疫情报备微信小程序,到底该怎么下手?”这个标题确实是计算机毕业设计里的高频选题,原因很直接:它把后端最常用的Spring Boot框架、数据库设计、小程序前端开发、接口联调这一整套流程全串起来了,做完等于把找工作要展示的全栈能力练了一遍。

这类项目的本质,是一个“居民端信息采集 + 管理端审核与统计”的双端应用。居民在微信里打开小程序填报健康信息、行程情况,社区管理人员在后台审核、汇总、导出,整个过程涉及用户登录、表单提交、数据审核、统计报表等一系列经典业务场景。对毕设来说,好处是需求明确、逻辑不复杂,但又有足够多的点可以深挖,比如权限控制、状态流转、数据可视化,很容易做到既有完整度又有亮点。

这篇文章我会从项目拆解、数据库设计、后端接口、小程序端实现、联调部署到答辩准备,一步步把关键细节讲透,适合正在做类似选题的同学直接参考,也适合想系统了解Spring Boot + 小程序项目怎么组织的开发者。

1. 项目整体拆解与需求设计

1.1 这个项目到底在做什么

很多同学拿到题目后第一反应是“疫情报备?是不是要先把业务流程搞清楚”。确实要先搞清楚,但别想复杂了。把业务抽象一下,它就是典型的“信息采集—审核—反馈”闭环:

  • 居民端:填写基本信息、健康情况、行程信息,提交报备,查看审核结果。
  • 管理端:查看待审核的报备单,逐个审核并填写意见,按社区或日期维度查看统计情况。
  • 系统端:维护用户身份、角色权限、报备记录、审核日志。

理解了这条主线,后面所有表设计和接口设计都是围绕它展开的。很多同学一上来就设计出十几张表,结果把自己绕晕。以我的经验,第一版先做“用户表 + 报备表 + 审核日志表”这三张核心表,跑通之后,再根据需求加社区表、消息通知表,这样节奏最稳。

1.2 角色划分与功能模块拆分

一个合格的毕设必须有清晰的权限模型。常见的设计是三角色:

角色使用端核心权限
居民微信小程序提交报备、查看个人记录、接收审核结果
社区审核员管理后台(Web)审核报备、查看本社区统计、导出数据
系统管理员管理后台(Web)管理用户、分配角色、查看全部数据、维护社区信息

这里需要注意,审核员和管理员的界面权限最好不一样。比如审核员只能看到自己社区的报备记录,管理员能看到全部。这是答辩时老师很容易追问的点:“你怎么控制数据权限?”如果你用的是MyBatis-Plus,最简单的做法是每次查询都带一个community_id条件,管理员不传,审核员强制传自己所属的社区ID。虽然粗暴,但逻辑清楚,好解释。

功能模块按端拆开,大致是:

  • 小程序端:用户授权登录、首页信息填报、历史记录查询、审核结果展示、个人中心。
  • 管理端:账号登录、Dashboard统计卡片、报备列表与详情、审核操作、社区管理、用户管理、数据导出。

1.3 为什么是Spring Boot + 微信小程序

这个选题能火,不是没有原因的。

从毕设的评审角度讲,Spring Boot生态非常成熟,资料多、上手快、坑少。Maven一键管理依赖,内嵌Tomcat不用单独装服务器,MyBatis-Plus能把大部分单表操作从手写SQL里解放出来,对于基础一般的同学来说,这套组合可以在两周内把后端骨架搭完,剩下的时间用来打磨细节。

从小程序端看,微信小程序天然适合这种“轻量、高频、用完即走”的工具型应用。用户不需要下载App,扫码或者搜索就能打开,非常贴近真实的社区服务场景。而且小程序的开发语言就是JavaScript + WXML + WXSS,前端基础语法和Vue很像,学起来不费劲。

从前端匹配度讲,Spring Boot提供RESTful接口,小程序用wx.request发起请求,JSON数据直接解析渲染,整个数据链路非常顺。用这个组合做毕设,技术上是“中规中矩但完整”,老师看着熟悉,你也好答辩,就业时还能写进简历,属于性价比很高的选择。

2. 数据库设计与接口规划

2.1 核心表结构设计

数据库设计是这类系统的重中之重。我见过太多同学把字段一股脑塞进一张表,后面越写越痛苦。这里我给出一个经过实际验证的推荐设计,直接照着改就行。

用户表(sys_user)

字段名类型说明
idbigint主键
openidvarchar(64)微信openid,小程序登录唯一标识
nicknamevarchar(50)用户昵称
phonevarchar(20)手机号
roletinyint角色:0=居民,1=审核员,2=管理员
community_idbigint所属社区ID,审核员必填
create_timedatetime创建时间

需要注意,openid一定要加唯一索引。这是用户身份的凭证,不能重复,否则登录逻辑会出问题。如果之后想支持手机号登录,再单独加一个username字段即可。

报备信息表(report_info)

字段名类型说明
idbigint主键
user_idbigint提交人ID
community_idbigint所属社区ID
report_datedate报备日期
health_statustinyint健康状态:1=正常,2=异常
temperaturedecimal(4,1)体温
contact_historyvarchar(255)行程/接触史描述
addressvarchar(255)当前地址
statustinyint审核状态:0=待审核,1=已通过,2=已驳回
audit_remarkvarchar(255)审核意见
create_timedatetime提交时间
audit_timedatetime审核时间

这张表是业务核心。status字段用数字而不是字符串,是为了后续索引和统计更方便。report_date单独拆出来,方便按天做统计,也避免和create_time混淆——用户可能在深夜提交,跨天了,业务日期和创建时间就分开了。

审核日志表(audit_log)

字段名类型说明
idbigint主键
report_idbigint报备id
auditor_idbigint审核人id
actiontinyint动作:1=通过,2=驳回
remarkvarchar(255)审核意见
create_timedatetime操作时间

千万不要省掉这张表。一方面它是答辩时的加分项,说明你考虑了操作留痕;另一方面,如果审核状态被误改,可以通过日志追溯。这是从真实业务里带出来的习惯,不是理论。

社区表(community)字段相对简单:id、名称、编码、联系人、联系电话。如果用户表挂了community_id,那么提交报备时就可以自动带入社区信息,不需要用户手选,体验会好很多。

2.2 接口清单与状态流转

后端接口不用多,但每个都要职责清晰。我建议的最小接口清单是:

  • POST /api/auth/login微信登录
  • GET /api/report/page分页查询报备列表(管理端用)
  • POST /api/report/submit提交报备(小程序端用)
  • GET /api/report/my查询我的报备记录
  • GET /api/report/detail/{id}报备详情
  • POST /api/report/audit审核接口
  • GET /api/report/stats统计接口
  • GET /api/community/list社区列表

状态流转很简单:0(待审核) -> 1(通过)/ 2(驳回)。需要注意驳回后,如果用户再次提交,要生成一条新报备单,而不是修改旧单。这个是业务规则,很多同学会搞错。为什么?因为报备是“某天的一次性行为”,如果允许修改历史记录,统计就会乱掉。每次提交都新增记录,才能保证数据维度规整。

2.3 字段与状态设计的几个坑

我写这类系统踩过几个典型的坑,提前说一下:

第一个坑是时间字段类型。report_date用date,create_time用datetime,两者语义不同。如果混用,按天统计时会出各种边界问题。另外MySQL 5.7以下的版本datetime默认不支持到毫秒,不用纠结,秒级足够。

第二个坑是小数精度。体温字段用decimal(4,1),能存36.5,别用float,float在数据库里是近似存储,做范围查询容易出幺蛾子。

第三个坑是状态字段加索引。status这个字段会频繁出现在查询条件里,不加索引,数据一多慢查询就来了。建表时顺手加上KEY idx_status (status),养成习惯。

第四个坑是软删除问题。用户表如果做了删除操作,一定要用逻辑删除(加deleted字段),不要物理删除。因为用户可能已经提交过报备,物理删除会导致关联数据悬空。用MyBatis-Plus的@TableLogic注解可以很优雅地处理。

3. 后端核心实现细节

3.1 项目初始化和依赖配置

后端我建议直接用Spring Boot 2.7.x版本,太新或太旧都可能遇到兼容性问题。创建项目用Spring Initializr,依赖勾选以下这几个:

  • Spring Web
  • MyBatis-Plus(注意Initializr里没有,需要手动加依赖)
  • MySQL Driver
  • Lombok
  • Redis(可选,用来存token)

pom.xml中需要额外添加MyBatis-Plus的依赖:

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.20</version> </dependency>

Druid不是必须的,用默认的HikariCP也完全没问题。加Druid主要是为了监控SQL执行情况,方便排查问题,如果你不想额外学配置,直接删掉也行。

application.yml里的核心配置:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/community_report?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

这里有一个关键点是serverTimezone=Asia/Shanghai。很多同学数据库连不上、时间差8小时,八成是没配时区。加了这个参数,同时保持MySQL的time_zone设置一致,能避免一堆莫名其妙的问题。

实体类直接用Lombok写,简洁。比如User实体:

@Data @TableName("sys_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String openid; private String nickname; private String phone; private Integer role; private Long communityId; private LocalDateTime createTime; @TableLogic private Integer deleted; }

3.2 微信登录与token机制

微信小程序登录的逻辑,说穿了就是两步:小程序端调用wx.login拿到code,后端拿着这个code去微信接口换openid。真实项目中还需要用openid换用户信息,但微信现在对用户昵称头像已经改成「头像昵称填写能力」,不再是自动获取的,所以毕设里只要拿到openid就能识别用户身份。

后端用一个工具类封装微信接口调用。核心代码:

public String code2Openid(String code) { String url = String.format( "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, code ); RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(url, String.class); JSONObject json = JSON.parseObject(response); return json.getString("openid"); }

拿到openid后,查用户表。如果用户不存在,自动创建一条新记录。这就是所谓的“静默注册”——用户第一次打开小程序授权后直接登录,不需要单独走注册流程。

登录成功后要给前端返回一个token。这里有两种做法:一种是生成UUID存Redis,另一种是用JWT生成一个带签名的token。我推荐JWT,因为毕设里少维护一套Redis,而且JWT的原理在答辩时很好讲。引入依赖:

<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency>

生成token:

String token = Jwts.builder() .setSubject(userId.toString()) .claim("role", user.getRole()) .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000)) .signWith(secretKey) .compact();

前端每次请求带上Authorization: Bearer {token},后端用一个拦截器解析并取用户信息。后续所有接口,只要在Controller里加一个自定义注解@CurrentUser,就能直接拿到当前登录用户。这是整个项目里最能提现功底的环节。

3.3 报备提交接口的校验与幂等

报备提交接口是业务核心,也是最容易被答辩老师深挖的地方。需要处理的细节很多。

先看参数校验。除了框架层面的@Validated注解,我建议对业务规则做手动校验。比如:

  • 体温必须在35.0到42.0之间(常识范围,超出肯定填错了)
  • 健康状态不能为空
  • 同一天不能重复提交(这一点非常关键)

同一天不能重复提交怎么实现?最简单的办法是在report_info表加上(user_id, report_date)唯一索引,然后在插入时捕获DuplicateKeyException,返回“今日已报备”的提示。这样比“先查再插”要靠谱,因为查询和插入之间有微小的时间窗口,并发时可能插入两条。用唯一索引直接掐死在数据库层面,逻辑上无懈可击。

提交接口的核心代码:

@PostMapping("/submit") public Result submit(@RequestBody ReportSubmitReq req, @CurrentUser User user) { // 参数校验 if (req.getTemperature() < 35.0 || req.getTemperature() > 42.0) { return Result.error("体温数据超出合理范围"); } // 组装实体 ReportInfo report = new ReportInfo(); report.setUserId(user.getId()); report.setCommunityId(user.getCommunityId()); report.setReportDate(LocalDate.now()); report.setHealthStatus(req.getHealthStatus()); report.setTemperature(req.getTemperature()); report.setContactHistory(req.getContactHistory()); report.setAddress(req.getAddress()); report.setStatus(0); // 入库,如果重复提交会抛异常 try { reportMapper.insert(report); } catch (DuplicateKeyException e) { return Result.error("今日已报备,请勿重复提交"); } return Result.success(report.getId()); }

这里我刻意没写address的必填校验。实际业务中,用户可能不愿意填具体门牌号,只愿意填到小区。所以隐私相关的字段,建议尽量宽松,只要用户选填或不填不影响业务闭环就行。这样设计既贴近真实需求,也能在答辩时讲出你的思考。

3.4 审核接口的事务与权限控制

审核操作涉及两件事:更新报备单状态 + 写入审核日志。这两个操作必须放在同一个事务里。用Spring的@Transactional注解就可以:

@Transactional(rollbackFor = Exception.class) public void audit(AuditReq req, User auditor) { // 1. 校验报备单存在且状态为待审核 ReportInfo report = reportMapper.selectById(req.getReportId()); if (report == null || report.getStatus() != 0) { throw new BusinessException("报备单不存在或已被处理"); } // 2. 数据权限校验:审核员不能审核其他社区的数据 if (auditor.getRole() == 1 && !auditor.getCommunityId().equals(report.getCommunityId())) { throw new BusinessException("无权操作该数据"); } // 3. 更新状态 report.setStatus(req.getAction()); report.setAuditRemark(req.getRemark()); report.setAuditTime(LocalDateTime.now()); reportMapper.updateById(report); // 4. 写日志 AuditLog log = new AuditLog(); log.setReportId(report.getId()); log.setAuditorId(auditor.getId()); log.setAction(req.getAction()); log.setRemark(req.getRemark()); auditLogMapper.insert(log); }

数据权限校验这段,是很多同学容易漏的。如果不加这个判断,审核员只要知道报备单ID,就能审核任意社区的数据。这是一个典型的越权漏洞,属于安全范畴,写出来会是很亮眼的加分点。

3.5 统计报表接口的实现

统计接口的核心是SQL按日期分组、按状态分组。推荐用MyBatis-Plus的QueryWrapper配合selectMaps,或者直接写XML里的自定义SQL。

我习惯于在Mapper里写一个自定义SQL:

@Select("SELECT report_date, COUNT(*) AS total, " + "SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS pending, " + "SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS approved, " + "SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS rejected " + "FROM report_info " + "WHERE community_id = #{communityId} " + "GROUP BY report_date " + "ORDER BY report_date DESC") List<Map<String, Object>> selectStatsByDate(@Param("communityId") Long communityId);

统计SQL的CASE WHEN写法是必须掌握的,比起在Java内存里循环统计,SQL一次性算完的效率高得多。如果要做近7天走势图,后端返回这个List,前端直接喂给ECharts或者小程序端的图表组件就行。

4. 小程序端实现要点

4.1 页面结构与路由设计

小程序端的页面不需要多,四五个就够:

页面路由功能
首页pages/index/index信息填报
记录页pages/records/records历史报备列表
详情页pages/detail/detail报备详情与审核状态
我的页pages/mine/mine个人中心,登录退出

核心页面是首页,布局一眼看过去要清楚:标题“今日健康信息报备”,下面是健康状态选择、体温输入、行程接触说明、地址填写,底部一个大的提交按钮。

这里要注意,小程序的原生组件picker可以做单选和多选,但健康状态这种二选一场景直接用两个radio或者样式化的按钮更好,用户操作路径更短。

app.json里配置页面路由和窗口样式:

{ "pages": [ "pages/index/index", "pages/records/records", "pages/detail/detail", "pages/mine/mine" ], "window": { "navigationBarTitleText": "社区健康报备", "navigationBarBackgroundColor": "#1989fa", "navigationBarTextStyle": "white" }, "permission": { "scope.userLocation": { "desc": "获取位置用于确认报备所在区域" } } }

4.2 表单提交与用户体验细节

表单这块有两个点要说。

第一个是提交按钮的防重复。小程序端网络慢的时候,用户可能连点两次提交,后端虽然有唯一索引兜底,但前端也要做一层防护。最简单的做法是定义一个submitting标志,提交后置为true,请求结束再恢复,期间按钮禁用并显示“提交中…”。

submit() { if (this.data.submitting) return; this.setData({ submitting: true }); wx.request({ url: api.reportSubmit, method: 'POST', data: formData, success: res => { wx.showToast({ title: '提交成功', icon: 'success' }); wx.navigateTo({ url: '/pages/records/records' }); }, complete: () => { this.setData({ submitting: false }); } }); }

第二个是表单校验。小程序的表单校验不要傻乎乎全交给后端,前端先拦一层,体验才好。手机号用正则/^1[3-9]\d{9}$/,体温先判断是否为空、再判断是否在合理范围,文字描述字段限制长度(比如最多200字),这些校验逻辑写在submit开头。

4.3 定位、消息通知与数据兜底

如果真的要用wx.getLocation自动获取当前位置,需要注意用户拒绝授权的情况。现实场景里用户大概率会拒绝,所以必须先判断授权状态:已授权就直接调用,未授权引导用户手动选择社区或手填地址,不允许因为拿不到定位就卡住流程。设计一个兜底方案,比设计一个理想化的自动化流程更见功底。

审核结果的通知,微信小程序支持“订阅消息”。用户提交报备时,调用wx.requestSubscribeMessage申请订阅,后端审核通过或驳回后,调用subscribeMessage.send发送通知。这一步的核心逻辑不复杂,麻烦的是要在小程序后台申请模板、拿到模板ID,审核后才会生效。如果毕设时间紧,可以先做一个页面上显示的审核状态轮询,消息通知作为加分项写进“后续优化”里。

小程序端的请求封装,我建议统一封装一个request.js。所有接口走同一个方法,自动带token、统一处理401跳转登录:

function request(url, method, data) { return new Promise((resolve, reject) => { wx.request({ url: baseUrl + url, method, data, header: { 'Authorization': 'Bearer ' + wx.getStorageSync('token') }, success: res => { if (res.data.code === 401) { wx.redirectTo({ url: '/pages/mine/mine' }); return; } resolve(res.data); }, fail: reject }); }); }

这个封装虽然代码不多,但整个项目的可用性全靠它。如果你不想在十几处地方重复写wx.request和错误处理,一定要做这一步。

5. 联调、测试与部署

5.1 本地联调的常见问题

本地联调是项目开发中最费时间的阶段,问题集中在这几个地方。

第一个是域名校验问题。小程序真机预览时,wx.request的域名必须是HTTPS并已在后台配置,但本地开发时还有一个“不校验合法域名”的选项。在开发者工具的“详情—本地设置”里勾上,本地http://localhost:8080就能直接访问。注意这个选项只在开发环境生效,上线时必须用正式HTTPS域名。

第二个是CORS跨域问题。如果小程序的request有跨域报错,后端要做全局跨域配置。Spring Boot里最简单的方法是写一个WebMvcConfigurer:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600); } }

需要注意的是,allowCredentials(true)时allowedOriginPatterns不能用"*",要用allowedOriginPatterns("*"),这是Spring Boot 2.4之后的规则,很多同学第一次配会报错。

第三个是MyBatis-Plus字段映射问题。数据库字段create_time对应实体属性createTime,在map-underscore-to-camel-case: true下能自动映射。但如果不小心用了@TableField又把fill策略配错了,导致新建记录时间字段为null,那就要检查MetaObjectHandler是否生效。

5.2 上线部署的几个要点

毕设如果需要上线演示,我建议用一台云服务器,配置不用高,2核4G足够。部署流程大致是:

# 打包 mvn clean package -DskipTests # 上传 jar 包到服务器 scp target/community-report.jar user@server:/opt/app/ # 启动 java -jar /opt/app/community-report.jar --spring.profiles.active=prod &

上线环境务必注意:

  • 数据库连接串改用服务器内网的数据库地址,不要用localhost想当然。
  • 所有HTTP接口必须走HTTPS,微信小程序正式版只认HTTPS域名。申请证书之后用Nginx做反向代理,配置证书,代理到后端8080端口。
  • 日志要输出到文件。在application-prod.yml里配置logging.file.name=/opt/logs/community-report.log,否则日志刷在控制台,出问题不好排查。

5.3 演示数据准备

很多同学程序写完没准备数据,答辩现场打开管理端,列表空空如也,效果大打折扣。一定要提前准备一套“有说服力”的演示数据。至少包含:

  • 近7天每天的报备统计数据,体现统计图表的效果。
  • 状态为“待审核”“已通过”“已驳回”的记录各一条,体现审核流程的完整性。
  • 不同社区的记录,体现数据隔离的逻辑。

演示数据可以直接往数据库里插,也可以写一个CommandLineRunner在项目启动时自动生成。我更推荐后者,因为可以随时重置数据,而且能在答辩时现场演示“初始化系统”的过程,比较直观。

6. 答辩准备与高频问题整理

6.1 演示路线的设计

演示顺序很重要,建议按这个顺序来,逻辑最顺:

先用小程序登录,演示提交一条报备(新用户自动注册),然后切到管理后台刷新列表,找到这条记录,执行审核并通过,再回到小程序查看记录状态变成“已通过”。整个闭环走完,评委对这个系统的功能就一目了然。如果时间充裕,再走到统计页面,展示按日期的报备趋势图,强调你做了数据维度分析。

6.2 高频问题与参考回答

问题1:为什么用Spring Boot而不是SSH/SSM?

回答思路:Spring Boot简化了配置,内嵌Tomcat,配合MyBatis-Plus开发效率高,生态成熟、资料多,文档完善。这不是说SSM不好,而是从工程实践角度Spring Boot更符合当前行业主流。

问题2:用户每天重复提交你是怎么处理的?

回答思路:数据库层面加了(user_id, report_date)唯一索引,结合异常捕获,从根源上保证同一用户同一天只能有一条记录。并发场景下也不会出现问题,因为唯一约束是数据库特性,不依赖业务代码的判断。

问题3:如果报备量很大,这个系统的性能瓶颈在哪?怎么优化?

回答思路:现阶段瓶颈可能在统计查询的SQL。优化思路有三个方向:第一,给status、community_id、report_date这些筛选字段加联合索引;第二,统计数据可以预先聚合到一张每日统计表,查询直接读聚合表;第三,报备提交高峰期可以用消息队列异步削峰。这类问题不求答得多深,能说出思路就赢了。

问题4:你的项目有什么亮点?

这个要提前准备好。推荐讲这两个:一是数据权限控制,审核员只能操作本社区的数据,通过拦截器统一处理;二是审核操作的事务一致性,报备状态变更和日志写入在同一个事务内,不会出现状态改了但日志没记上的情况。

我的几个实操建议

项目写到一半,最容易崩心态的不是代码写不出来,而是“不知道下一步该干嘛”。我的习惯是先把数据库表建好,再按“登录接口→提交接口→审核接口→统计接口”的顺序一个一个打通,每打通一个就立刻用接口测试工具验证一遍,不积压问题。

还有一个很实用的技巧:从一开始就统一接口返回格式,比如code + message + data。所有前端都依赖这个结构,中途改格式会导致大量返工,别问我怎么知道的。

最后说一点个人感受。这种双端项目最忌讳“只顾功能不管边界”。拿到题目之后先花一个小时想清楚业务流程、角色权限、数据流转,后面写代码就是体力活。很多同学跳进细节里出不来,反而误了进度。按上面这套思路走,项目质量至少能超过六成同类毕设,答辩也更有底气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询