从业务系统开发到AI应用:小白程序员一周升维指南(收藏版)
2026/8/9 0:22:03
把“写论文”当成一次小创业,AI 不是替你写代码的枪手,而是随时待命的“技术合伙人”。
去年指导学弟做“校园二手书交易平台”,他吭哧吭哧写了 3 周,结果演示当天被三连问:
典型症状总结如下:
getParameter→convert→validate→dao.insert(),Ctrl C/V 到怀疑人生。';drop table user;--直接社死。uid存进隐藏域,刷新就丢;或者把密码明文塞进session,服务器一重启全员下线。| 维度 | 传统手写 | AI 辅助(GitHub Copilot + 通义灵码) |
|---|---|---|
| DAO 层模板 | 30 min/表 | 1 min 生成,带PreparedStatement |
| 表单验证 | 自己写正则,易遗漏 | 一键提示ValidationUtils,自动提示 OWASP 正则 |
| XSS 过滤 | 后期统一替换<c:out> | 生成 JSP 时自动加c:out/fn:escapeXml |
| 安全漏洞扫描 | 人眼 review | 插件实时标红,提示 CSRF、SQL 注入 |
| 代码行数 | 2 k+ | 700 行左右,结构清晰 |
结论:AI 不会替你思考业务,但能瞬间给出“安全、可维护”的骨架,让你把精力放到“故事线”和“创新点”。
功能清单:注册、登录、书籍列表、详情页、注销。技术栈:JSP + Servlet 3.1 + MySQL 8 + HikariCP。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.3.0</version> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency>AI 提示词:“java web maven dependency mysql connection pool”直接给出最新坐标,避免抄旧博客的 5.x 驱动。
public enum DBPool { INSTANCE; private final HikariDataSource ds; DBPool() { HikariConfig cfg = new HikariConfig(); cfg.setJdbcUrl("jdbc:mysql://localhost:3306/bookdb?useSSL=false&serverTimezone=UTC"); cfg.setUsername("root"); cfg.setPassword("root"); cfg.addDataSourceProperty("cachePrepStmts", "true"); cfg.addDataSourceProperty("prepStmtCacheSize", "250"); ds = new HikariDataSource(cfg); } public Connection getConn() throws SQLException { return ds.getConnection(); } }AI 补全:键入HikariConfig cfg = new后,Copilot 自动提示常用参数,避免手写拼写错误。
public class UserDAO { private static final String INSERT_SQL = "INSERT INTO user(username,password) VALUES (?,?)"; public boolean insert(User u) { try (Connection c = DBPool.INSTANCE.getConn(); PreparedStatement ps = c.prepareStatement(INSERT_SQL)) { ps.setString(1, u.getUsername()); ps.setString(2, BCrypt.hashpw(u.getPassword(), BCrypt.gensalt())); return ps.executeUpdate() > 0; } catch (SQLException e) { throw new DAOException("User insert fail", e); } } public User findByUsername(String username) { String sql = "SELECT id,password FROM user WHERE username=?"; try (Connection c = DBPool.INSTANCE.getConn(); PreparedStatement ps = c.prepareStatement(sql)) { ps.setString(1, username); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return new User(rs.getInt(1), username, rs.getString(2)); } } } catch (SQLException e) { throw new DAOException("User find fail", e); } return null; } }AI 提示:键入ps.set后自动循环补齐字段,避免漏列;异常封装DAOException也是插件推荐模板。
@WebFilter(filterName = "csrfFilter", urlPatterns = "/*") public class CsrfFilter implements Filter { private static final String CSRF_KEY = "csrf"; public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest r = (HttpServletRequest) req; HttpServletResponse resp = (HttpServletResponse) res; r.setCharacterEncoding("UTF-8"); if ("POST".equalsIgnoreCase(r.getMethod())) { String client = r.getParameter(CSRF_KEY); String server = (String) r.getSession().getAttribute(CSRF_KEY); if (client == null || !client.equals(server)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Bad CSRF"); return; } } chain.doFilter(req, res); } }AI 补全:输入if (client == null ||自动给出.equals(server),避免==坑。
<jsp:useBean id="bookList" type="java.util.List<com.book.bean.Book>" scope="request"/> <table> <c:forEach items="${bookList}" var="b"> <tr> <td><c:out value="${b.title}"/></td> <td><c:out value="${b.author}"/></td> </tr> </c:forEach> </table>AI 提示:打出<c:forEach自动补全items与var,并提示加c:out防 XSS。
.jsp→.java→.class,Tomcat 10 本地测试多 200 ms;可通过jsp_precompile在 Maven 打包期完成,或改用前后端分离(毕设若必须 JSP,提前访问一次热身即可)。StandardManager把session放内存,200 人同时在线约 60 MB;调低<session-timeout>15</session-timeout>并在web.xml配置maxActiveSessions。| 风险 | 本项目做法 |
|---|---|
| 注入 | 统一PreparedStatement,AI 拒绝拼接 |
| 失效身份认证 | 登录后存userId+ 随机sessionId,退出即invalidate() |
| 敏感数据暴露 | 密码BCrypt哈希,数据库连接密码放 JNDI 或环境变量 |
| XSS | JSP 全部<c:out>逃逸 |
| CSRF | 过滤器统一校验 |
| 安全 misconfig | 生产关闭server.info头,Tomcat 自带ErrorReportValve |
<sql:query>——看上去方便,实则把业务逻辑锁进表现层,导师一眼扣分。ErrorServlet接web.xml的<error-page>,记录堆栈后跳转到友好页面,避免直接把 500 抛给用户。DefaultServlet列表,减少目录遍历风险。System.out,改用SLF4J + Logback,AI 会提示占位符写法:log.info("user {} login", username)。Servlet遗留模块(比如“订单删除”)。PreparedStatement模板 + 事务模板,但手动给方法、变量起符合业务的名称。只有当你能独立重构 AI 给出的代码,才证明它真的帮你“毕业”了。
写完长舒一口气:AI 把最脏最累的样板活揽了,我省下的时间用来画用例图、写创新点,导师终于夸“代码结构清晰,工作量饱满”。可我心里清楚,如果只会Tab接代码,迟早要还技术债。下一晚,我关掉插件,把最早写死的“用户密码 123456”逐条改成随机密钥,那一刻才感觉——毕业设计,真的成了自己的作品。