1. 通配符
用于配置action:
<package name="registerAction" extends="struts-default">
<action name="user_*" class="com.cityu.b_action.RegisterAction" method="{1}">
<result name = "success">/{1}.jsp</result>
<result name = "fail">/index.jsp</result>
</action>
</package>
因此,JSP页面的下列表单项将会提交到user_register.action(也就是RegisterAction)中的register方法,如果result返回”success”,则会转发到register.jsp页面:
<form action="${pageContext.request.contextPath}/user_register.action" method = "post">
2. Struts中常量配置/国际化举例
在org.apache.struts2包default.properties文件中配置
可以在用户自定义的struts.xml文件中通过常量配置完成一些全局配置
例如国际化:
步骤:
写资源文件–>struts常量加载–>struts标签引入
首先,写资源文件com/cityu/b_action/msg.properties,其中是国际化的name-value对:形如login=\u767B\u9646
- Msg.properties: 默认语言环境
- Msg_en_US.properties:英语
然后,通过常量加载资源文件:
<constant name = "struts.custom.i18n.resources" value = "com/cityu/b_action/msg"></constant>
最后,在JSP页面中引入:
<%@taglib uri = "/struts-tags" prefix = "s"%>
<s:text name = "login"></s:text>
注意:国际化资源文件也可以在JSP用struts的i18n标签引入,但是这种方法不推荐!
1)修改访问后缀
<constant name = "struts.action.extension" value = "action,,"></constant>
2)动态方法调用
action name=”user”
/user!login—>访问user对应的action类中的login()方法
3. 全局配置
1)全局跳转视图
<struts>
<package name="helloaction" extends="struts-default">
<global-results>
<result name = "success">/data_test.jsp</result>
</global-results>
<action name="data" class="com.cityu.action.HelloActioin" method="execute">
</action>
</package>
</struts>
注意需要配置在action节点前面
- “+”一个或者多个;
- “?”没有或者一个;
- “*”没有或者一个或者多个
2)配置各项默认值
如果没有指定类:
<action name = "test"></action>
那么会执行默认的类com.opensymphony.xwork2.ActionSupport中的execute方法,并且返回值是”success”,会去跳转全局视图中找success对应的页面,这种方法,常用与用于页面转发:默认转发,可以跳转到WEB-INF目录下的资源(重定向redirect,不能访问WEB-INF下的资源—处于安全性考虑!)
4. 核心业务
4.1 请求数据自动封装
过程是由参数拦截器实现的,用户访问时,创建Action类对象,此时已经获得了Action中的属性,方法;提交表单数据后,会经过params拦截器
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
对表单提交的数据进行封装(封装过程会使用到Action中的属性、方法),然后将封装后的结果返回给Action中的数据对象。
4.2 类型转换
jsp提交的数据(一般都是String类型),struts会自动转换为Action中对应的属性类型;对于基本类型,字符串类型会自动封装,而其他类型需要使用自定义类型转换器封装。
1) 自定义类型转换类,继承StrutsTypeConverter类
public class MyConverter extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
try {
return sdf.parse(values[0]);
} catch (ParseException e) {
throw new RuntimeException("converter failed!!");
}
}
@Override
public String convertToString(Map context, Object o) {
return null;
}
}
2) 配置转换器类
在需要类型转换的Action类同一个包路径下新建配置文件,命名为:
RegisterAction-conversion.properties
在其中配置需要转换的数据类型:提交的字符串—>封装类型
user.birthday=com.cityu.b_action.MyConverter
虽然转换器类是全局通用的,但是由于这个配置文件的原因,只能给RegisterAction提供转换,这被称为局部类型转换器。
3)全局类型转换器
类型转换器类是不用修改的!
配置,在src/下:xwork-conversion.properties
java.util.Date=com.cityu.b_action.MyConverter
4) 优化转换器类:
public class MyConverter extends StrutsTypeConverter{
SimpleDateFormat[] df = {
new SimpleDateFormat("yyyyMMdd"),
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyy年MM月dd日")
};
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
if(values == null || values.length==0){
return null;
}
if (toClass!=java.util.Date.class) {
return null;
}
//可以处理三种输入格式的转换
for (SimpleDateFormat sdf : df) {
try {
return sdf.parse(values[0]);
} catch (ParseException e) {
continue;
}
}
return null;
}
@Override
public String convertToString(Map context, Object o) {
return null;
}
}
4.3 数据处理的几种方式
1)拿到ServletApi执行操作
<struts>
<package name="helloaction" extends="struts-default">
<global-results>
<result name = "success">/data_test.jsp</result>
</global-results>
<action name="data" class="com.cityu.action.HelloActioin" method="execute">
</action>
</package>
</struts>
public class HelloActioin implements Action{
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext application = ServletActionContext.getServletContext();
request.setAttribute("request_data", "hello_request");
session.setAttribute("session_data", "hello_session");
application.setAttribute("application_data", "hello_application");
return SUCCESS;
}
}
2) 使用ActionContext类
public class HelloActioin implements Action{
@Override
public String execute() throws Exception {
ActionContext ac = ActionContext.getContext();
Map<String, Object> request = ac.getContextMap();
Map<String, Object> session = ac.getSession();
Map<String, Object> application = ac.getApplication();
request.put("request_data", "hello_request2");
session.put("session_data", "hello_session2");
application.put("application_data", "hello_application2");
return SUCCESS;
}
}
这种方式,没有必要使用Servlet的API,是一种解耦的方式,推荐!
但是,在必须使用Servlet的API时(例如通过request拿到当前的项目路径等等),没有办法去使用封装的map形式。
3) 通过实现接口来注入map对象
public class HelloActioin extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
@Override
public String execute() throws Exception {
request.put("request_data", "hello1");
session.put("session_data", "hello2");
application.put("application_data", "hello3");
return SUCCESS;
}
}
这种方式,也有解耦的效果。并且在action的业务方法比较多的时候,不需要每次都从ActionContext容器中去取域对象。这种方式已经通过接口在全局注入了域对象,可以在多个业务方法中使用。这种获取域对象的方式,通常在写BaseAction,做优化处理时使用。
4.4 文件上传
传统JSP/Servlet模型实现方式:
前台
- 提交方式POST
- 表单类型 multipart/form-data
- input type = file
后台
Apache提供的FileUpload组件
核心API:
FileItemFactory
ServletFileUpload
FileItem
总之,文件上传在servlet中实现时比较麻烦的!
Struts框架可以简化:前台无法简化(JSP规范),后台如何简化?