第一次跑通Struts2的程序时候,我盯着浏览器里那句“Hello World”愣了好几秒。程序不是程序激动,是程序困惑——就这么个破页面,居然要配web.xml、程序struts.xml,程序还要写Action类、程序JSP,程序绕这么大一圈?程序后来才明白,框架解决的程序根本不是“输出一句话”的问题,而是程序“请求进来之后,代码该怎么组织”的程序秩序感。
先别急着写代码。程序你得有个能跑的程序Web容器,Tomcat就行,程序版本别太老。然后建个Dynamic Web Project,把Struts2的jar包扔进WEB-INF/lib。这一步最烦人,因为依赖关系跟蜘蛛网似的——commons-lang3、ognl、javassist……少一个就报ClassNotFoundException。我当年卡在这上面整整一下午,最后发现是忘了拷freemarker。
真正的入口是web.xml。里面挂一个Filter,名字叫struts2,指向org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter。注意,老版本的类名是FilterDispatcher,已经被废弃了。你要是从网上抄旧教程,十有八九会在这里踩坑。配好之后,所有请求都会先经过这个过滤器,由它决定该交给哪个Action处理。
接着写Action类。别被名字吓住,它就是个普通Java类,里面放一个execute()方法,返回字符串。比如:
public class HelloAction { private String message; public String execute() { this.message = "第一个Struts2程序"; return "success"; } // getter/setter省略 } 返回值不是随便写的。它对应struts.xml里的逻辑视图名。所以还得建一个struts.xml,放在src根目录下。里面写package、action、result三件套。package像命名空间,action定义URL和类的映射,result决定跳转页面。我的配置文件长这样:
<package name="default" extends="struts-default"> <action name="hello" class="com.example.HelloAction"> <result name="success">/hello.jsp</result> </action> </package> 注意extends="struts-default",这行不能省。它把框架内置的拦截器、默认结果类型都继承过来了。少了它,Action里的方法根本不会被调用,页面直接404。
最后写个JSP展示结果。用EL表达式取message属性:
<body> <p>${ message}</p> </body> 然后启动Tomcat,浏览器访问http://localhost:8080/你的项目名/hello。看到页面显示“第一个Struts2程序”,就算成了。
整个过程里最反直觉的地方在于——你写的Action类其实是个POJO,它不继承任何框架基类,也不实现特定接口。Struts2通过反射和配置文件把请求参数塞进属性,再调用execute()。这种设计比Struts1的ActionForm清爽多了,但代价是配置文件里字符串拼写错误很难被编译器发现。我见过有人把“success”拼成“sucess”,结果页面跳转失败,日志里查了半天。
还有个小细节。struts.xml里action的name属性就是URL后缀,但不带.action后缀。框架默认会匹配.do和.action两种扩展名。你要是想改,可以在配置里设置struts.action.extension,不过新手阶段别折腾,用默认的就好。
现在回看那个“Hello World”,它真正教会你的是MVC的分层思维——请求被Filter拦截,Action处理业务逻辑,JSP只负责渲染。这个骨架一旦立起来,后面加用户登录、表单校验、文件上传,都是往这个框架里填肉。当然,Struts2的漏洞史也够写本书了,但那是后话。至少第一个程序跑通时,你对“请求如何流转”会有一个直观的体感。
哦对了,如果你用的Tomcat 10以上版本,记得换Jakarta命名空间的Servlet API,否则过滤器类会找不到。这坑我替你们踩过了。
