2008年的SSH入门门槛——插入一个用户要配多少东西

2008年的SSH入门门槛------插入一个用户要配多少东西

Struts 1.1 + Spring 2.0 + Hibernate 3。这是2008年Java Web开发的"标准三件套"。那时候写一个"插入用户"功能,不是今天的三行代码,是在五层配置文件里找到了正确的标签、配对了正确的依赖链。这篇文章是一个当年的SSH学习项目,逐步拆解"插入一条用户记录"到底经历了多少层。

文章目录


一、背景:2008年的SSH三件套

2008年做Java Web,开口就是SSH------Struts做MVC,Spring做容器,Hibernate做ORM。不是选其中一个,是三个都要用,少一个就不叫"企业级"。

当时的入门门槛不是理解概念,是把这三个东西配通。因为它们不是一个爹生的------Struts是Apache的,Spring是SpringSource的,Hibernate是JBoss的。三个不同组织开发的框架要在一个项目里合作,全靠XML配置把它们的接触点手工接上。

一个最简单的"插入用户"功能,经历的层数是今天Spring Boot的十倍。


二、Struts 1------前端的请求入口

xml 复制代码
<!-- struts-config.xml -->
<form-beans>
    <form-bean name="userform" type="com.myssh.form.UserForm"/>
</form-beans>

<action-mappings>
    <action path="/user"
            type="com.myssh.action.UserAction"
            parameter="status">
        <forward name="success" path="/success.jsp"/>
        <forward name="fail" path="/fail.jsp"/>
    </action>
</action-mappings>

前端JSP用 <html:form action="/user.do?status=insert"> 提交表单。Struts 1的 ActionServlet 拦截 *.do,读到 path="/user",根据 parameter="status"insert 值找到 UserAction 里的 insert() 方法。

jsp 复制代码
<!-- test.jsp -->
<html:form action="/user.do?status=insert">
    用户名:<html:text property="username"/>
    密码:<html:password property="password"/>
    <html:submit>提交</html:submit>
</html:form>

Struts 1 的 ActionForm 要把表单字段一个一个人肉声明:

java 复制代码
public class UserForm extends ActionForm {
    private String username;
    private String password;
    // getter/setter... 每个字段都要写
}

今天一个 @RequestParam@ModelAttribute 的事,那时要写一个完整的ActionForm类。


三、Spring 2------IOC容器把三层串起来

xml 复制代码
<!-- applicationContext.xml -->
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
    <property name="username" value="YFSI"/>
    <property name="password" value="YFSI"/>
</bean>

<!-- Hibernate Session工厂 -->
<bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list><value>com/myssh/po/User.hbm.xml</value></list>
    </property>
</bean>

<!-- DAO -->
<bean id="iuserdao" class="com.myssh.dao.impl.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!-- Service -->
<bean id="iuserservice" class="com.myssh.service.impl.UserServiceImpl">
    <property name="iuserdao" ref="iuserdao"/>
</bean>

<!-- Action(Struts与Spring的接触点) -->
<bean name="/user" class="com.myssh.action.UserAction">
    <property name="iuserservice" ref="iuserservice"/>
</bean>

依赖注入链:UserAction → UserServiceImpl → UserDaoImpl → SessionFactory → DataSource。每个节点都是XML里一个 <bean> 标签。

注意Action的bean name是 /user------它必须和 struts-config.xml 里的 path="/user" 对得上。这是Struts和Spring之间唯一的连接点,配错了Struts找不到Action。


四、Struts与Spring的桥接------DelegatingRequestProcessor

xml 复制代码
<!-- struts-config.xml -->
<controller>
    <set-property property="processorClass"
                  value="org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>

这一行是整个SSH集成的关键。Struts 1默认用 RequestProcessor 创建Action实例。DelegatingRequestProcessor 把它劫持了------创建Action时不自己 new,而是去Spring容器里按 path 名称查找bean。

所以Action的bean name必须和struts-config里的path一致------这就是SSH时代"Struts认path、Spring认beanName"的设计约定。不对上就是一串 NullPointerException


五、Hibernate 3------对象到Oracle表的映射

xml 复制代码
<!-- User.hbm.xml -->
<hibernate-mapping>
    <class name="com.myssh.po.User" table="user1" schema="YFSI">
        <id name="id" column="id" type="integer">
            <generator class="increment"/>
        </id>
        <property name="username" column="username" type="string"/>
        <property name="password" column="password" type="string"/>
    </class>
</hibernate-mapping>

POJO只有三个字段------id、username、password。但每个字段都要在XML里显式声明类型、列名、映射关系。今天 @Entity + @Column 的事,那时候是一份独立的XML文件。


六、DAO实现------HibernateDaoSupport

java 复制代码
public class UserDaoImpl extends HibernateDaoSupport implements IUserDao {
    public boolean insert(User user) {
        try {
            this.getHibernateTemplate().save(user);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

HibernateDaoSupport 是Spring对Hibernate的封装------通过 getHibernateTemplate() 拿到模板对象,调 save()update()delete()。这个模式的好处是:不用手动开Session、不用管事务、不用close连接。Spring帮你管了。

但代价也很明显------你要继承 HibernateDaoSupport,破坏了自己DAO的继承体系。如果你的DAO还需要继承别的基类,就没法做了。


七、完整调用链------从JSP到Oracle的五层传递

复制代码
test.jsp
  │ POST /user.do?status=insert
  ▼
ActionServlet (*.do路由)
  │
  ▼
DelegatingRequestProcessor(从Spring容器取Action)
  │
  ▼
UserAction.insert()
  │ 从ActionForm取出username/password
  │ 构造User PO
  │ 调 iuserservice.insert(user)
  ▼
UserServiceImpl.insert()
  │ 调 iuserdao.insert(user)
  ▼
UserDaoImpl.insert()
  │ 调 getHibernateTemplate().save(user)
  ▼
Hibernate → INSERT INTO YFSI.user1 VALUES(1, 'admin', '123456')
  │
  ▼
返回 success.jsp 或 fail.jsp

从点击提交到执行SQL,穿过六层。每一步都靠XML配置把接口和实现串起来。今天的Spring Boot让你感觉"写一个功能只要三行代码"------不是功能真的简化了,是这六层的XML配置全被Spring Boot自动配置替代了


八、SSH时代的三座大山

当年的痛苦 今天的解法
web.xml配置 手动配Servlet/Taglib/ContextLoader Spring Boot自动注册
Struts-Spring桥接 DelegatingRequestProcessor配错就404 Spring MVC原生集成
Hibernate映射 每张表一个hbm.xml JPA注解 + @Entity
依赖注入 每个bean一个 <property> @Autowired自动装配
事务管理 HibernateTransactionManager手配 @Transactional一个注解

一个插入用户的Demo,配置文件的篇幅是业务代码的三倍。这不是过度设计------是这三个框架设计之初就是独立的,合在一起全靠XML粘合剂。理解了这套粘合剂,就知道后来的Spring Boot消灭了什么。


九、结语

2008年的SSH学习成本不在Java本身------在配通三套框架的接触点。Struts认path,Spring认beanName,Hibernate认mappingResource,三者之间的对应关系全靠人脑记住。这套SSH三件套统治了Java Web开发整整五年,直到2013年Spring Boot出现,一键消灭了这堆XML。

现在回头看这个只有"插入用户"的项目,代码不到100行,配置超过200行。它不是复杂------是那个年代的技术选型就是这样的。理解了它,就理解了Spring Boot为什么能一统天下。