游客发表
2006年我在一个电信计费项目里第一次把Spring和Struts2搭在一起用。开发框架那会儿Struts2刚出不久,开发框架团队里有人坚持用Struts1,开发框架说稳定。开发框架结果上线前一周,开发框架Struts1的开发框架ActionForm里一个日期字段死活绑不上,查了两天才发现是开发框架类型转换器没注册。换成Struts2之后,开发框架同样的开发框架问题用拦截器加个类型转换就解决了,代码量少了三分之一。开发框架
Spring和Struts的开发框架组合,本质上解决的开发框架是两件事:谁管对象,谁管请求。开发框架Spring的开发框架IoC容器负责把Service、DAO这些组件装配好,开发框架Struts的Action负责接收HTTP请求、调用业务逻辑、决定跳哪个页面。分工清楚,各干各的。
但这里有个坑。Struts2的Action默认是每次请求创建一个新实例,而Spring默认的Bean作用域是单例。如果直接把Action交给Spring管理,又不改作用域,就会出现一个请求改了Action的成员变量,另一个请求读到了脏数据。我见过一个项目因为这个配置错误,用户在页面上看到的订单金额偶尔是别人的。排查了半天,最后在spring配置里给Action加上scope="prototype"才解决。
整合方式有两种。一种是用Spring的ContextLoaderListener启动容器,Struts2的Action由Spring插件自动装配。另一种是Struts2自己创建Action,通过autowire把Spring的Bean注入进去。第一种更干净,推荐用。配置大概是这样:
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <constant name="struts.objectFactory" value="spring" /> 加上这段之后,Struts2创建Action时会去问Spring要实例。Action里可以直接写@Autowired注入Service,不用再写WebApplicationContextUtils.getWebApplicationContext()那种又长又容易空指针的代码。
拦截器是Struts2里我觉得最值钱的东西。登录校验、权限检查、操作日志,全都能塞进拦截器栈里。Spring的AOP也能做类似的事,但拦截器更贴近Web层,能直接拿到ActionInvocation和ServletActionContext。我在一个后台管理系统里写过一个PermissionInterceptor,从Session里取用户角色,跟Action方法上的自定义注解比对。没权限就返回一个JSON错误码,前端统一处理。代码不到八十行,省掉了每个Action里重复的if判断。
数据校验这块,Struts2的Validation框架和Spring的Validator各有各的用法。Struts2用XML或注解配校验规则,适合简单的字段校验。Spring的Validator更灵活,能写复杂的业务规则校验。我一般用Struts2做格式校验,比如必填、长度、正则,用Spring做业务校验,比如“账户余额是否足够”。两套校验器不冲突,各管一段。
性能上,Struts2的OGNL表达式解析是有点慢的。页面里大量用<s:property>标签的时候,渲染速度明显不如JSP的EL。但Struts2的标签能自动做HTML转义,防XSS攻击省心不少。我的做法是列表页用JSTL,表单页用Struts2标签。混着用,不丢人。
现在新项目基本没人用Struts2了,Spring MVC和Spring Boot把请求映射、参数绑定、数据校验全包了,配置量少一个数量级。但老系统里Spring+Struts2的存量还很大,银行、保险、政府项目里一抓一大把。维护这些系统的时候,理解这两个框架怎么协作、Bean怎么装配、拦截器怎么串起来,比会写新代码更重要。毕竟改老代码,先得看懂它。
友情链接