命名空间
namespace决定了action的访问路径,也就是namespace里面写了什么,你的请求地址栏里就必须要包括什么。
namespace默认为“”,可以接收到所有路径的action,可以写为/,/xxx,/xxx/yyy 对应的访问路径就应该为/xxx/xxx.action,/xxx/yyy/xxx.action
namespace最好用模块来命名。
如下代码:
<constant name="struts.devMode" value="true" />
<package name="login" namespace="/login" extends="struts-default">
<action name="login">
<result>/login_success.jsp</result>
</action>
</package>
constant name="struts.devMode" value="true" 为调试模式开启(IDEA无法调用此功能,调试须重新部署)
package *name*属性用来区分重名的情况。
=====================================================================
Action
struts.xml内代码如下:
<package name="path" namespace="/path" extends="struts-default">
<action name="path" class="test.example">
<result name="success">
/path.jsp
</result>
</action>
</package>
action标签里的class值为你在src目录创建的JavaAction类的路径
Action操作类我用继承了一个ActionSupport类,类里包含了一些预设好了的对象和属性供开发者利用,后续struts2的Action类也都将继承此类。
在此处我重载了ActionSupport里的execute()方法,返回了一个值为“success”的String对象。
execute()为默认执行的方法,即在上面的配置文件里的action标签内,你不声明method属性时默认执行的方法。
example.java代码如下:
package test;
import com.opensymphony.xwork2.ActionSupport;
/**
* Created by Alex on 2017/5/8.
*/
public class example extends ActionSupport{
@Override
public String execute(){
return "success";//result默认值为success
}
}
这个action类返回一个“success”的String至struts.xml,里面的result标签负责接收这个值,其中name属性为结果值,默认为"success"
也就是说 若返回值为success,那么result标签内就不用再写name属性。
另外一种action类的的写法,此方法为主流方法,可以自定义方法名来进行开发操作,而不仅仅局限与execute()这一种方法。
另外返回值我们利用了SUCCESS这一在父类ActionSupport中接口Action中的变量值,
可看到struts2的源码中为我们内置了这些变量值:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.opensymphony.xwork2;
public interface Action {
String SUCCESS = "success";
String NONE = "none";
String ERROR = "error";
String INPUT = "input";
String LOGIN = "login";
String execute() throws Exception;
}
Action代码如下:
package action;
import com.opensymphony.xwork2.ActionSupport;
/**
* Created by Alex on 2017/5/9.
*/
public class CourseAction extends ActionSupport {
public String add(){
return SUCCESS; //接口包含变量
}
public String delete(){
return SUCCESS;
}
}
可以看到此处我们不在重载execute方法,而是选择自定义命名的方法,那么在struts.xml里面我们应该如何接受返回值?
请看
<package name="actions" namespace="/actions" extends="struts-default">
<action name="course" class="action.CourseAction" method="add">
<result>
/User_add_success.jsp
</result>
</action>
<action name="course" class="action.CourseAction" method="delete">
<result>
/User_delete_success.jsp
</result>
</action>
</package>
可以看到,在此处action标签内我们编写了一个method属性,里面的值就是我们action类里自定义方法的名称
这样一来,我们就可以通过这种方法来调用自定义的方法了。
=====================================================================
通配符
上面的代码大家有没有觉得很冗余,其实我们可以精简一点通配符的运用:
struts.xml
<package name="actions" namespace="/actions" extends="struts-default">
<action name="*_*" class="action.{1}Action" method="{2}" >
<result>
/{1}_{2}_success.jsp
</result>
</action>
</package>
可以看到action的name值变为了*_*, 这些*就代表了我们要传(要变)的参数,可以为add,可以为delete等等,后面的{1}{2}分别代表了第一个*所代表的值与第二个*所代表的值,依次代入,就可以实现动态接受与判断数据了。
配置代码是不是精简了很多?但是需要遵循约定优于配置这个原则
对应action类与jsp页面
=====================================================================
用Action的属性接收参数
package action;
import com.opensymphony.xwork2.ActionSupport;
/**
* Created by Alex on 2017/5/9.
*/
public class UserAction extends ActionSupport{
private String name;
private int age;
public String add(){
System.out.println("name:"+name);
System.out.println("age:"+age);
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
可以看到这种方式可以接收到页面传递过来的参数值,并进行处理。 但是这种传参模式有缺点,就是如果变量过多,会导致代码异常冗余
用DomainModel接受参数
package bean;
/**
* Created by Alex on 2017/5/9.
*/
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package action;
import bean.User;
import com.opensymphony.xwork2.ActionSupport;
/**
* Created by Alex on 2017/5/9.
*/
public class UserAction2 extends ActionSupport{
private User user; //实例化User实体类
public String add(){
System.out.println("username:"+user.getName());
System.out.println("username:"+user.getAge());
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
这种方式我们称之为 DomainModel 预模型
DTO(VO\DO)
用ModelDriven接收参数
package action;
import bean.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* Created by Alex on 2017/5/11.
*/
public class UserAction3 extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public String add(){
System.out.println("name"+user.getName());
System.out.println("name"+user.getAge());
return SUCCESS;
}
@Override
public User getModel(){
return user;
}
}
2.1.6版本的中文问题
<constand name=“struts.i18n.encoding" value="utf-8" />
若版本在2.1.7以下,则可用过滤器的方式来进行转码
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* Created by Alex on 2017/5/11.
*/
@WebFilter(filterName = "EncodingFilter")
public class EncodingFilter implements Filter {
public void destroy() {
}//过滤器销毁
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}//过滤器初始化
}
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
更改为:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URLEncoding="utf-8" />
即可修复中文输入乱码问题
简单的数据验证
<package name="actions" namespace="/actions" extends="struts-default">
<action name="user2" class="action.UserAction2">
<result> /User_add_success.jsp </result>
<result name="error">/user_add_error.jsp</result>
</action>
</package>
此处有两个result代表了两种处理情况,成功与失败
package action;
import com.opensymphony.xwork2.ActionSupport;
/**
* Created by Alex on 2017/5/11.
*/
public class LoginAction extends ActionSupport {
private String name;
public String add(){
if(name==null || !name.equals("fjnmbb12")){
this.addFieldError("name","name is error");
return ERROR;
}
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
可以看到这里add()内有两种情况,返回了不同的结果。其中发生错误的结果内有一个addFieldError方法,此方法将会发送错误的原因至前端页面。
<%--
Created by IntelliJ IDEA.
User: Alex
Date: 2017/5/11
Time: 22:32
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<title>Title</title>
</head>
<body>
用户添加异常!
<s:fielderror fieldName="name" theme="simple" /> <br/>
<s:property value="errors.name[0]"/> <br/>
<s:debug></s:debug>
</body>
</html>
在前端页面我们引用了struts 的标签,首先在顶部插入引用语,
访问Web元素
<%--
Created by IntelliJ IDEA.
User: Alex
Date: 2017/5/10
Time: 16:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="http://localhost:8080/">
<title>$Title$</title>
</head>
<body>
<form action="" id="f" name="f" method="post">
<input type="text" name="name" placeholder="输入用户名" /><br />
<input type="password" name="password" placeholder="输入密码" /> <br />
<input type="button" value="提交1" οnclick="javascript:document.f.action='login/login1';document.f.submit();" />
<input type="button" value="提交2" οnclick="javascript:document.f.action='login/login2';document.f.submit();" />
<input type="button" value="提交3" οnclick="javascript:document.f.action='login/login3';document.f.submit();" />
<input type="button" value="提交4" οnclick="javascript:document.f.action='login/login4';document.f.submit();" />
</form>
</body>
</html>
<package name="login" namespace="/login" extends="struts-default">
<action name="login*" class="action.LoginAction{1}">
<result>/login_success.jsp</result>
</action>
</package>
package action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import javax.net.ssl.SSLSessionContext;
import java.util.Map;
/**
* Created by Alex on 2017/5/10.
*/
public class LoginAction1 extends ActionSupport{
private Map request;//声明类型为Map的request变量
private Map session;//声明类型为Map的session变量
private Map application;//声明类型为Map的application变量
public LoginAction1(){
//调用ActionSupport内的方法对三大对象进行取值
request = (Map)ActionContext.getContext().get("request");
session=ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
}
@Override
public String execute(){
request.put("r1","r1");
session.put("s1","s1");
application.put("a1","a1");
return SUCCESS;
}
}
package action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import java.util.Map;
/**
* Created by Alex on 2017/5/10.
*/
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String,Object> request;
private Map<String,Object> session;
private Map<String,Object> application;
public String execute(){
request.put("r1","r2");
session.put("s1","s2");
application.put("a1","a2");
return SUCCESS;
}
@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;
}
}
Action总结
- 实现一个Action的最常用的方式:从ActionSupport继承
- DMI动态方法调用 !xxx
- 通配符配置 * {1} {2}
- *_*
- 接收参数的方法(一般用属性和DomainModel来接收)
- 简单的数据验证 addFieldError
- 一般不使用struts2的ui标签
- 访问WEB元素
- Map类型(1、IoC 2、依赖struts2)
- 原始类型 (1、IoC 2、依赖struts2)
- 包含文件配置(include标签)
- 默认action处理