当前位置: 首页 > news >正文

2004年的Java项目翻出来了我哭了——一个老程序员的回忆杀

2004年的 Java 项目翻出来了我哭了——一个老程序员的回忆杀

前几天整理旧硬盘,翻出了web_sy这个项目。文件时间戳显示2004年9月 ~ 2005年1月。那是我学 Java 的第一年,写出的第一个"能跑"的系统。20年后的今天再看这些代码,我笑着笑着就哭了。


这个项目是什么?

这是一个社保信息系统(JBMIS),运行在:

  • WebLogic 8.1.2(BEA 公司,后来被 Oracle 收购了)
  • Oracle 数据库jdbc:oracle:thin:@localhost:1521:orcl
  • EJB 2.0(Stateless Session Bean)
  • Servlet + XML(前后端通信全靠 XML 字符串)

项目名web_sy——“sy” 大概是"实验"或"实习"的缩写。从命名就能看出来,这是一个练手项目。


回忆杀一:那个 XML 通信协议

2004年没有 RESTful,没有 JSON,前后端通信全靠手搓 XML:

<Program><FunctionID>80001</FunctionID><parameters><aab001>320123456789012345</aab001><password>123456</password></parameters></Program>

Servlet 收到 XML → 解析出FunctionID→ 查数据库找到对应的 Java 类名 →Class.forName(className).newInstance()动态加载 → 执行业务逻辑 → 返回 XML。

这就是我当年理解的"框架":

// myServlet.java - 核心分发逻辑Func_Id=XMLFunc.getFuncIDFromDoc(doc);strClassName=SysFunc.getClassNameByFuncIdFromDB(Func_Id);curBusiFunc=(BusiFunc)Class.forName(strClassName).newInstance();retCode=curBusiFunc.Run(doc);retMsg=curBusiFunc.getMessage();

现在回头看,这不就是一个简陋版的Spring MVC 的 @RequestMapping吗?只不过 Spring 用注解,我用数据库查表。

那个BusiFunc接口:

publicinterfaceBusiFunc{publicintRun(Documentdoc);publicStringgetMessage();}

不就是现在 Controller 的雏形吗?


回忆杀二:那个年代没有 JSON

整个系统前后端的数据序列化全靠手写 XML DOM

// XMLFunc.java - 把 ResultSet 转成 XMLwhile(rs.next()){iRow++;nRow=doc.createElement("row"+iRow);for(iLoop=0;iLoop<iFields;iLoop++){sKey=(String)fields.get(iLoop);nField=doc.createElement(sKey.toLowerCase());sValue=rs.getString(sKey);if(!rs.wasNull()){sValue=newString(sValue.getBytes("ISO8859_1"),"GBK");// 经典的编码转换nValue=doc.createTextNode(sValue);nField.appendChild(nValue);}nRow.appendChild(nField);}nRs.appendChild(nRow);}

每一行数据就是一个<row1><row2>…每个字段是一个 XML 节点。没有 Jackson,没有 Gson,XML 全靠 DOM API 一点一点拼

看到new String(sValue.getBytes("ISO8859_1"), "GBK")这行了吗?每个 Java 程序员都写过这样的编码转换。2004年,中文编码是最大的噩梦。


回忆杀三:那个 EJB 2.0 的 Hello World

jsp/ejb/目录下有一个完整的 EJB 2.0 示例。EJB 2.0 写一个 “Hello World” 需要多少个文件?

至少4个

远程接口(Remote Interface)

publicinterfaceHelloextendsEJBObject{publicStringsayHello()throwsRemoteException;}

Home 接口

publicinterfaceHelloHomeextendsEJBHome{Hellocreate()throwsCreateException,RemoteException;}

Bean 实现类

publicclassHelloBeanimplementsSessionBean{privateSessionContextctx;privateStringwords;publicvoidsetSessionContext(SessionContextctx){this.ctx=ctx;}publicvoidejbActivate(){}publicvoidejbPassivate(){}publicvoidejbRemove(){}publicvoidejbCreate()throwsCreateException{words="Hello World";}publicStringsayHello(){System.out.println("I am in an EJB of Server ."+words);returnwords;}}

客户端调用

Propertiesh=newProperties();h.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");h.put(Context.PROVIDER_URL,"t3://localhost:7001");Contextctx=newInitialContext(h);Objecthome=ctx.lookup("HelloHome");HelloHomehelloHome=(HelloHome)PortableRemoteObject.narrow(home,HelloHome.class);Hellohello=helloHome.create();System.out.println(hello.sayHello());

就为了打印一个 “Hello World”,你需要写 Home 接口、Remote 接口、Bean 类、客户端,还要写两个 XML 配置文件(ejb-jar.xmlweblogic-ejb-jar.xml),然后打包成.jar,再用 WebLogic 的工具生成.ear

现在 Spring Boot 一个注解@RestController搞定。当年的 Java EE 是真的重。


回忆杀四:那个连接池

数据库连接的获取方式:

DrivermyDriver=(Driver)Class.forName("weblogic.jdbc.pool.Driver").newInstance();lconn=myDriver.connect("jdbc:weblogic:pool:OraclePool",null);

用的是WebLogic 的连接池,通过config.xml配置:

<JDBCConnectionPoolDriverName="oracle.jdbc.driver.OracleDriver"Name="OraclePool"Password="{3DES}n7C1FaJNa5k="Properties="user=jbmis"Targets="myserver"TestTableName="dual"URL="jdbc:oracle:thin:@localhost:1521:orcl"/>

密码用 3DES 加密存储——这在当年算是"安全"的了。现在谁还在config.xml里明文写数据库配置?都用 Nacos/Apollo 配置中心了。

还有一个test()方法:

privatestaticConnectiontest(){Class.forName("oracle.jdbc.driver.OracleDriver");StringlUrl="jdbc:oracle:thin:@10.81.193.8:1521:hygeia";conn=DriverManager.getConnection(lUrl,"insur_test","test");returnconn;}

内网 IP10.81.193.8,数据库 SIDhygeia(Hygeia 是希腊健康女神),用户名insur_test——这些信息告诉我,这是一个真实的社保/医保系统的开发环境。


回忆杀五:那个代码风格

SQL 注入风险

StringcsSql="SELECT aab001,password,sn FROM user_ab01 where AAB001 = '"+csAAB001+"'";

字符串拼接 SQL,没有任何防注入处理。2004年,PreparedStatement已经存在了,但我在查询时还是用了字符串拼接。只有在更新操作时才用了PreparedStatement——大概是因为更新时参数太多,拼接太麻烦。

密码明文比较

if(!csPassWord.equals(dpassword)){this.iFlag=-1;this.strErr="ERR,密码不正确!";}

密码明文存储、明文比较。没有 MD5,没有加盐哈希,更没有 BCrypt。那个年代大家都是这么干的

错误码硬编码

this.iFlag=-411002016;this.strErr="获取参数时出错";

错误码像电话号码一样:-411002016-490002165-411002090…完全没有枚举,没有常量定义,纯硬编码。现在看到这些数字,我已经完全不记得每个码代表什么了。

finally 中 return

finally{try{if(this.conn!=null&&!this.conn.isClosed()){this.conn.close();}}catch(SQLExceptionex){this.iFlag=-411002091;return(this.iFlag);// finally 块中的 return!}}

在 finally 块中 return,这是 Java 的反模式,会吞掉 try 块中的异常。但现在看,当年我根本不知道这个规则。


回忆杀六:那些 AW/Swing 练习

jsp/目录下还有一些MouseDemo3.javamyDialog.javaourButton.java——这些是用AWT/Swing写的桌面程序练习。

// MouseDemo3.java - 鼠标画线程序publicvoidmouseDragged(MouseEvente){flag=2;x=e.getX();y=e.getY();repaint();}

还有一个极其简单的 JSP:

<HTML> <BODY> Hello! The time is now <%= new java.util.Date() %> </BODY> </HTML>

这大概是那个年代每个人的第一个 JSP 吧。


回忆杀七:那个编码问题

整个项目的中文注释全是 GBK 编码,用现代编辑器打开全是乱码:

// ÔÚXMLÎĵµÖдÓParameters½ÚµãÖеÄÈ«²¿×Ó½ÚµãÈ¡³ö // ×÷ΪkeyÖµÌí¼Óµ½HashtableÖзµ»Ø

Avector.java里甚至有一行直接是乱码的中文:

中文内容 v.setElementAt("four",4);

这不是 bug,是 GBK 编码在 UTF-8 环境下的惨剧。当年每个项目都要处理编码问题,现在谁还操心这个?


回忆杀八:那个深夜加班

看文件时间戳:

2004/11/21 00:16:50 a.jsp 2004/12/15 23:23:32 JBSetAC01_sy.java 2004/12/15 23:24:14 JBSetAC01_sy.class 2004/12/16 01:32:08 JBSetAC01_zj.class 2004/12/16 01:36:30 JBSetAB01.java

凌晨1点半还在写代码JBSetAC01_sy(失业)、JBSetAC01_zj(在职)、JBSetAC01_js(就业)——社保系统的各种人员状态,一个状态写一个类,凌晨还在加班。

20年前如此,20年后…也是如此。程序员的加班宿命,从未改变。


回忆杀九:那个自学路线

从时间戳可以还原当年的学习路线:

2004/09 Servlet 基础 2004/11 XML 解析(DOM)、数据库操作、工具类 2004/11 EJB 2.0(Stateless Session Bean) 2004/11 AWT/Swing 桌面编程 2004/12 业务功能开发(社保系统 CRUD) 2005/01 收尾、打包

那是一个没有 Maven、没有 Gradle、没有 Spring的年代:

  • 依赖管理?手动拷贝.jar文件
  • 项目构建?写个build.bat或者直接在 IDE 里点"编译"
  • 部署?把.war.ear丢到 WebLogic 的applications目录
  • 版本控制?这个项目根本没有.svn.vss目录,可能连版本管理都没用

20年后的感悟

2004年2024年
WebLogic 8.1Spring Boot 3.x
EJB 2.0Spring @Service
XML DOM 解析Jackson/Gson
Servlet + XMLRESTful + JSON
手动管理连接池HikariCP + MyBatis
字符串拼接 SQLMyBatis/JPA
GBK 编码噩梦统一 UTF-8
无版本管理Git + GitHub/GitLab
深夜加班写代码深夜加班写代码

20年过去了,技术栈换了三轮,但深夜加班这一点从来没变。

看这些代码的感觉很复杂:既为自己当年的笨拙感到好笑,又为那种不怕困难、从零开始的学习劲头感到怀念。那时候没有 StackOverflow,没有 ChatGPT,遇到问题只能翻书和查 API 文档。

那个写Class.forName(strClassName).newInstance()的年轻人不会想到,20年后他会在一个完全不同的技术栈上做架构师,但那个"用反射动态加载业务类"的思想,他用了整整20年。


那些消失的东西

  • BEA WebLogic— 被 Oracle 收购,风光不再
  • EJB— 被 Spring 彻底取代
  • XML 配置— 被注解和 YAML 替代
  • AWT/Swing— 被 Web 前端取代
  • ISO8859_1/GBK— 被 UTF-8 统一
  • 那个 10.81.193.8 的开发服务器— 大概早就报废了

但那个在凌晨1点半还在调代码的人,还在。


写在2024年,一个看了20年前代码的老程序员的眼泪。

http://www.jsqmd.com/news/750086/

相关文章:

  • 别再傻傻分不清!手机卡顿、电脑慢?可能是你的EMMC、UFS、SSD没选对
  • 内容创作平台集成 Taotoken 实现多模型文本生成与优化
  • AT24C02页写翻车实录:我的参数为什么被覆盖了?详解EEPROM页边界与防覆盖技巧
  • 提升arm7开发效率:快马智能生成常用驱动与模块代码库
  • 5步解锁NVIDIA显卡隐藏性能的完整指南:NVIDIA Profile Inspector实战教程
  • 语音数据集选择与应用实践指南
  • Higgsfield:简化多节点大模型训练的分布式编排框架实战指南
  • 第2篇:数据与类型——仓颉的基础数据类型 仓颉原生中文编程
  • Mac终极音乐解密指南:3步解锁QQ音乐加密文件,实现跨平台自由播放
  • 低代码插件热重载失败?(从py_compile缓存污染到__pycache__权限锁死的完整排障链)
  • Xiaomusic插件架构源码级解析:动态加载与异步事件处理机制深度剖析
  • 别再只会用滤镜了!用Python+OpenCV手把手教你调出专业级照片锐化效果(USM/SM实战)
  • 立即解决!Windows任务栏透明美化神器TranslucentTB全攻略
  • 工业备料封神!郑州博尚木材切片机实测,精度拉满还省电,木材厂/加工厂必入 - 会飞的懒猪
  • 数据格式混乱、时间戳错位、主键冲突全解析,深度解读Python跨系统融合的7大隐形陷阱
  • WaveTools鸣潮工具箱:终极解决方案,3分钟告别游戏卡顿与抽卡烦恼
  • ESP32边缘语音识别控制机械爪:从TensorFlow Lite到舵机控制的完整实践
  • 京东二面:假如SQL中join了10张表,如何优化性能?
  • 从零到自动化:用NetBox + NAPALM打造你的网络‘活地图’(含API调用实战)
  • 项目实训(五):面向 AI 解释的 SQL 注入传播链记录
  • 如何在5分钟内解锁你的加密音乐收藏:Unlock-Music完整指南
  • 2026年武汉微电影制作拍摄公司TOP7权威排行榜,为你揭晓行业佼佼者! - 品牌推荐官方
  • 魔兽争霸3终极助手:3步配置WarcraftHelper解锁宽屏与高帧率
  • 城通网盘下载太慢?这个免费神器让你秒变下载达人!
  • 别再手动降噪了!用FFmpeg的arnndn+AI模型,批量处理播客录音真香
  • 如何实现Unity游戏实时翻译:XUnity.AutoTranslator技术深度解析
  • 30秒生成CSDN技术博客封面!GPT-Image-2适配平台规范的参数配置指南
  • EasyClick 双端自动化智能体|AndroidiOS 全平台 EC 脚本开发助手
  • MOOTDX:量化投资中的通达信数据整合技术突破
  • 新手如何通过快马平台轻松上手windows18-hd19主题开发项目