关于Struts2中Action从表单取值并且存到Web元素中(session)
2010-04-17 18:21
453 查看
在struts2中,Action不同于struts1.x中的Action。在struts2中Action并不需要继承任何控制器类型或实现相应接口。比如struts1.x中的Action需要继承Action或者DispatcherAction。
同时struts2中的Action并不需要借助于像struts1.x中的ActionForm获取表单的数据。可以直接通过与表单元素相同名称的数据成员(需要存在符合命名规范的set和get方法)获取页面表单数据。
虽然struts2中的Action原则上不用继承任何类型。但是一般需要实现com.opensymphony.xwork2.Action接口或者继承com.opensymphony.xwork2.ActionSupport类型,然后重写execute方法。通常更愿意去继承ActionSupport类型,这样我们可以在我们的控制器中增加更多的功能。因为ActionSupport本身不但实现了Action接口,而且实现了其他的几个接口,让我们的控制器的功能更加强大,例如:
com.opensymphony.xwork2.Validateable:提供了validate方法,可以对action中的数据进行校验
com.opensymphony.xwork2.ValidationAware:提供了addFieldError方法,可以存取action级别或者字段级别的错误消息
com.opensymphony.xwork2.TextProvider:提供了获取本地化信息文本的方法getText
com.opensymphony.xwork2.LocaleProvider:提供了getLocale方法,用于获取本地信息
从以上我们可以看到,继承ActionSupport,可以完成更多的工作。
例如上面的例子,例如我们需要判断输入文本框的内容,输入的内容长度必须在6-10之间。那么我们可以增加校验工作,利用validate方法。更改后的代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String message;
private String username;
@Override
public String execute() throws Exception {
this.message="Hello World:"+this.username;
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public void validate() {
if(this.username.trim().length()<6||this.username.trim().length()>10){
addFieldError("user.username","the length is invalid");
}
}
}
由于实现了validate方法,这样当请求一个控制器(在这里为helloWorld.action)的时候,首先执行validate方法,如果有错误信息增加到action中,那么就不继续执行Action,返回INPUT,否则就继续执行Action。在本例中,首先判断用户名称是否在合法的长度范围,如果不在增加错误信息,返回INPUT(默认返回)。
因为有错误返回INPUT,所以此Action在配置文件中应该定义INPUT转发路径
<action name="helloWorld" class="com.frank.action.HelloWorldAction">
<result name="success">display.jsp</result>
<result name="input">helloWorld.jsp</result>
</action>
出现错误时,返回到helloWorld.jsp,并在此页面中显示控制器中所注册的错误消息,更改后的页面如下(黑色字体为增加的)
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'helloWorld.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1><s:fielderror/></h1><br>
<form action="helloWorld.action">
username:<s:textfield name="username"/>
<br>
<s:submit align="left"/>
</form>
</body>
</html>
当前Action执行的核心方法都是execute,有时我们可以能希望同一个控制器做不同的工作。例如在对一个表分别进行CRUD操作时,我们可能需要根据不同的情况执行4种操作,这样一个execute做起来比较麻烦,我们可以定义我们自己的方法,然后控制器有选择的执行。类似struts1.x中的DispatcherAction控制器一样。
这时我们自定义的操作方法,必须和execute具有相同的签名,只是名称不同而已。例如在前面的例子中我们增加一个超链接,让它同样请求helloWorld.action,但是在控制器端执行自己定义的方法myExecute。注意在这里先去掉验证方法validate,取消验证。修改后代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String message;
private String username;
@Override
public String execute() throws Exception {
this.message="Hello World:"+this.username;
return SUCCESS;
}
public String myExecute() throws Exception{
this.message="Good Morning !!!";
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
此时我们需要增加新的Action配置,并指明调用的方法
<action name="otherHelloWorld" class="com.frank.action.HelloWorldAction" method="myExecute">
<result name="success">display.jsp</result>
</action>
在helloWorld.jsp中增加超链接,强求新增加的Action
<a href="otherHelloWorld.action">OtherAction</a>
新的请求页面:
点击超链接后,请求新的Action,结果如下:
由于请求的新Action在配置中指明了所调用的方法为myExecute,所以在控制器端不再执行execute方法,转而执行myExecute,所以输出结果为
即:Action名!新的方法名.action,刚才的超链接可以更改成:<a href="helloWorld!myExecute.action">OtherAction</a>
表单数据的提交
表单数据的提交在Web编程中是非常重要的。控制器需要获取用户在表示层(页面)所提交的数据,然后进行下一步操作。比如在用户登录操作中,控制器需要获取用户在页面中输入的“用户名称”和“密码”数据,来决定下一步的验证。
获取表单提交的数据有两种方式:
第一种为使用中介对象(我通常把它称为包装表示层数据的包裹)。比如在strtus1.x中使用各种ActionForm来封装页面数据。使用中介对象可以同时在中介对象的里面增加诸如:验证、过滤、日志记录等附加工作。但是同样带来了类数量的膨胀,存在各种各样的ActionForm类(LoginForm、PersonForm等等),不利于项目的维护管理。
第二种是直接使用控制器中的域对象,即直接使用控制器中的数据成员获取表示层的数据,在struts2种支持此种方式。但必须保证相应的数据成员和表示层提交的数据名称一致,并且具有符合命名规范的setter和getter方法。这样可以达到“内省”。直接使用域对象可以减少类的膨胀,如果只是简单的获取提交的数据则建议直接使用域对象。
在此我们还是同一个非常简单的(我经常采用的)登录操作来体会开发过程。可以通过此操作扩展到复杂的操作,其实原理一样。还是从头开始(省去准备工作的步骤,直接进入开发过程):
首先创建一个登录页面login.jsp,代码内容如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1><s:fielderror/></h1>
<h1>User Login</h1><br>
<form action="login.action">
Username:<s:textfield name="username"/><br>
Password:<s:textfield name="password"/><br>
<input type="submit" value="Login"/>
</form>
</body>
</html>
<s:fielderror/>用于显示所注册的错误信息
接着建立Actiion类:LoginAction,在此我们通过域对象获取表示层提交的数据,也就是在控制器中声明两个数据成员username和password来得到表示层的数据,然后在execute方法中进行验证工作(当然,一般规范开发需要在业务类中进行实际验证),在此简便此操作。同时重写validate方法在Action实际执行前进行验证工作,具体的验证方式由自己的业务决定。代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String username;
private String password;
@Override
public String execute() throws Exception {
if(this.username.equals("admin")&&this.password.equals("admin")){
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(this.username==null||this.username.trim().length()<1){
addFieldError("no.username","must input username");
}
if(this.password==null||this.password.trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
新建一个index.jsp页面,用户在用户登录成功后显示,内容非常的简单,就是一条“Login Success!!!”
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1>Login Success!!!</h1>
</body>
</html>
现在可以开始配置Action了,在struts.xml中增加新的Action,配置如下:
<action name="login" class="com.frank.action.LoginAction">
<result>index.jsp</result>
<result name="input">login.jsp</result>
</action>
可以部署和运行了,启动login.jsp
如果在任意一个文本框中不输入内容或者输入空白内容,则返回当前页面,并错误提示
如果输入的用户名和密码错误,同样返回到当前页面
如果输入的用户和密码正确,则到达index.jsp
注意以上所有的提交方式都为默认GET提交方式
封装表示层数据到业务类中
在实际的开发过程中,我们可以用业务类对象获取表示层数据,这样我们可以在业务类中实现更多的业务方法(比如登录、注册)。而由控制器去调用业务类。因为struts2同样遵循的是MVC模式,所以我们不应该让控制器去做实际的业务工作,而是调用Model,而这里同样用Model获取表示层的数据。
这样我们可以新建一个类User,在这里声明数据成员username和password,并增加一个验证方法login,用于验证登录。User类的代码如下:
package com.frank.rule;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean login(){
if(this.username.equals("admin")&&password.equals("admin")){
return true;
}
return false;
}
}
既然我们用User获取用户的数据,这样我们需要在Action增加User类型的数据成员,而去掉原来的username和password,重构的代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends ActionSupport {
private User user;
@Override
public String execute() throws Exception {
if(user.login()){
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
在这里页面的数据不再由控制器的username和password数据成员获取,转而有其中的user对象进行封装。所以应该修改login.jsp的提交表单,修改后的结果如下:
<form action="login.action">
Username:<s:textfield name="user.username"/><br>
Password:<s:textfield name="user.password"/><br>
<input type="submit" value="Login"/>
</form>
注意此时提交表单中的文本框名称必须为user.username和user.password,这样所输入的内容会由控制器的user对象获取。
这里可能有一个疑问,就是在控制器中并没有在任何时候创建User对象,那么内容是如何获得的呢?难道不会抛出NullPointerException?此时当请求控制器,并设置user对象的username数据成员时,action依次调用下方法:
user.getUser();
user.setUser(new User());
user.getUser().setUsername("admin");
从上可以看出,首先struts2会尝试获取user对象,如果不存在则执行第二步创建一个新对象,然后将内赋给数据成员
重新部署,运行,所得到的效果和前一个相同。
使用Servlet相关对象
在进行Web编程时,很多时候需要使用Servlet相关对象,例如:HttpServletRequest、HttpServletResponse、HttpSession、ServletContext。我们可以将一些信息存放到session中,然后在需要的时候取出。
在struts1.x的Action中,可以通过HttpServletRequest和HttpServletResponse参数来得到Servlet相关对象,进而使用。那么在struts2种如何获取?
我们可以使用com.opensymphony.xwork2.ActionContext类来完成上述操作。此类的getContext方法可以得到当前Action的上下文,也就是当前Action所处的容器环境,进而得到相关对象。
同时也可以使用org.apache.struts2.ServletActionContext类获得,例如:
HttpServletRequest req=ServletActionContext.getRequest();
下面更改前面的登录操作,在登录成功后,将登录人员的信息保存到session范围中,在index.jsp页面中取出,我们可以重构我们的Action,在重构前,首先新增一个BaseAction,作为所有Action的父类,在其中增加方法获取Servlet相关对象,这样所有的子类都拥有了相应的方法。代码如下:
package com.frank.action;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
public class BaseAction extends ActionSupport {
public HttpServletRequest request(){
return ServletActionContext.getRequest();
}
public HttpServletResponse response(){
return ServletActionContext.getResponse();
}
public ServletContext application(){
return ServletActionContext.getServletContext();
}
public HttpSession session(){
return ServletActionContext.getRequest().getSession();
}
}
然后重构LoginAction,继承自BaseAction,并在登录成功后再session范围保存用户名信息,以便index.jsp读取,重构后代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends BaseAction {
private User user;
@Override
public String execute() throws Exception {
if(user.login()){
this.session().setAttribute("username", user.getUsername());
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
在index.jsp中增加读取session中保存内容的代码,如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1>Login Success!!!</h1>
<br>
<h1>Username:<%=session.getAttribute("username") %></h1>
</body>
</html>
同时struts2中的Action并不需要借助于像struts1.x中的ActionForm获取表单的数据。可以直接通过与表单元素相同名称的数据成员(需要存在符合命名规范的set和get方法)获取页面表单数据。
虽然struts2中的Action原则上不用继承任何类型。但是一般需要实现com.opensymphony.xwork2.Action接口或者继承com.opensymphony.xwork2.ActionSupport类型,然后重写execute方法。通常更愿意去继承ActionSupport类型,这样我们可以在我们的控制器中增加更多的功能。因为ActionSupport本身不但实现了Action接口,而且实现了其他的几个接口,让我们的控制器的功能更加强大,例如:
com.opensymphony.xwork2.Validateable:提供了validate方法,可以对action中的数据进行校验
com.opensymphony.xwork2.ValidationAware:提供了addFieldError方法,可以存取action级别或者字段级别的错误消息
com.opensymphony.xwork2.TextProvider:提供了获取本地化信息文本的方法getText
com.opensymphony.xwork2.LocaleProvider:提供了getLocale方法,用于获取本地信息
从以上我们可以看到,继承ActionSupport,可以完成更多的工作。
例如上面的例子,例如我们需要判断输入文本框的内容,输入的内容长度必须在6-10之间。那么我们可以增加校验工作,利用validate方法。更改后的代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String message;
private String username;
@Override
public String execute() throws Exception {
this.message="Hello World:"+this.username;
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public void validate() {
if(this.username.trim().length()<6||this.username.trim().length()>10){
addFieldError("user.username","the length is invalid");
}
}
}
由于实现了validate方法,这样当请求一个控制器(在这里为helloWorld.action)的时候,首先执行validate方法,如果有错误信息增加到action中,那么就不继续执行Action,返回INPUT,否则就继续执行Action。在本例中,首先判断用户名称是否在合法的长度范围,如果不在增加错误信息,返回INPUT(默认返回)。
因为有错误返回INPUT,所以此Action在配置文件中应该定义INPUT转发路径
<action name="helloWorld" class="com.frank.action.HelloWorldAction">
<result name="success">display.jsp</result>
<result name="input">helloWorld.jsp</result>
</action>
出现错误时,返回到helloWorld.jsp,并在此页面中显示控制器中所注册的错误消息,更改后的页面如下(黑色字体为增加的)
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'helloWorld.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1><s:fielderror/></h1><br>
<form action="helloWorld.action">
username:<s:textfield name="username"/>
<br>
<s:submit align="left"/>
</form>
</body>
</html>
当前Action执行的核心方法都是execute,有时我们可以能希望同一个控制器做不同的工作。例如在对一个表分别进行CRUD操作时,我们可能需要根据不同的情况执行4种操作,这样一个execute做起来比较麻烦,我们可以定义我们自己的方法,然后控制器有选择的执行。类似struts1.x中的DispatcherAction控制器一样。
这时我们自定义的操作方法,必须和execute具有相同的签名,只是名称不同而已。例如在前面的例子中我们增加一个超链接,让它同样请求helloWorld.action,但是在控制器端执行自己定义的方法myExecute。注意在这里先去掉验证方法validate,取消验证。修改后代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String message;
private String username;
@Override
public String execute() throws Exception {
this.message="Hello World:"+this.username;
return SUCCESS;
}
public String myExecute() throws Exception{
this.message="Good Morning !!!";
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
此时我们需要增加新的Action配置,并指明调用的方法
<action name="otherHelloWorld" class="com.frank.action.HelloWorldAction" method="myExecute">
<result name="success">display.jsp</result>
</action>
在helloWorld.jsp中增加超链接,强求新增加的Action
<a href="otherHelloWorld.action">OtherAction</a>
新的请求页面:
点击超链接后,请求新的Action,结果如下:
由于请求的新Action在配置中指明了所调用的方法为myExecute,所以在控制器端不再执行execute方法,转而执行myExecute,所以输出结果为
Good Morning !!!
同样存在另外一种形式请求新的Action:即:Action名!新的方法名.action,刚才的超链接可以更改成:<a href="helloWorld!myExecute.action">OtherAction</a>
表单数据的提交
表单数据的提交在Web编程中是非常重要的。控制器需要获取用户在表示层(页面)所提交的数据,然后进行下一步操作。比如在用户登录操作中,控制器需要获取用户在页面中输入的“用户名称”和“密码”数据,来决定下一步的验证。
获取表单提交的数据有两种方式:
第一种为使用中介对象(我通常把它称为包装表示层数据的包裹)。比如在strtus1.x中使用各种ActionForm来封装页面数据。使用中介对象可以同时在中介对象的里面增加诸如:验证、过滤、日志记录等附加工作。但是同样带来了类数量的膨胀,存在各种各样的ActionForm类(LoginForm、PersonForm等等),不利于项目的维护管理。
第二种是直接使用控制器中的域对象,即直接使用控制器中的数据成员获取表示层的数据,在struts2种支持此种方式。但必须保证相应的数据成员和表示层提交的数据名称一致,并且具有符合命名规范的setter和getter方法。这样可以达到“内省”。直接使用域对象可以减少类的膨胀,如果只是简单的获取提交的数据则建议直接使用域对象。
在此我们还是同一个非常简单的(我经常采用的)登录操作来体会开发过程。可以通过此操作扩展到复杂的操作,其实原理一样。还是从头开始(省去准备工作的步骤,直接进入开发过程):
首先创建一个登录页面login.jsp,代码内容如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1><s:fielderror/></h1>
<h1>User Login</h1><br>
<form action="login.action">
Username:<s:textfield name="username"/><br>
Password:<s:textfield name="password"/><br>
<input type="submit" value="Login"/>
</form>
</body>
</html>
<s:fielderror/>用于显示所注册的错误信息
接着建立Actiion类:LoginAction,在此我们通过域对象获取表示层提交的数据,也就是在控制器中声明两个数据成员username和password来得到表示层的数据,然后在execute方法中进行验证工作(当然,一般规范开发需要在业务类中进行实际验证),在此简便此操作。同时重写validate方法在Action实际执行前进行验证工作,具体的验证方式由自己的业务决定。代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String username;
private String password;
@Override
public String execute() throws Exception {
if(this.username.equals("admin")&&this.password.equals("admin")){
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(this.username==null||this.username.trim().length()<1){
addFieldError("no.username","must input username");
}
if(this.password==null||this.password.trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
新建一个index.jsp页面,用户在用户登录成功后显示,内容非常的简单,就是一条“Login Success!!!”
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1>Login Success!!!</h1>
</body>
</html>
现在可以开始配置Action了,在struts.xml中增加新的Action,配置如下:
<action name="login" class="com.frank.action.LoginAction">
<result>index.jsp</result>
<result name="input">login.jsp</result>
</action>
可以部署和运行了,启动login.jsp
如果在任意一个文本框中不输入内容或者输入空白内容,则返回当前页面,并错误提示
如果输入的用户名和密码错误,同样返回到当前页面
如果输入的用户和密码正确,则到达index.jsp
注意以上所有的提交方式都为默认GET提交方式
封装表示层数据到业务类中
在实际的开发过程中,我们可以用业务类对象获取表示层数据,这样我们可以在业务类中实现更多的业务方法(比如登录、注册)。而由控制器去调用业务类。因为struts2同样遵循的是MVC模式,所以我们不应该让控制器去做实际的业务工作,而是调用Model,而这里同样用Model获取表示层的数据。
这样我们可以新建一个类User,在这里声明数据成员username和password,并增加一个验证方法login,用于验证登录。User类的代码如下:
package com.frank.rule;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean login(){
if(this.username.equals("admin")&&password.equals("admin")){
return true;
}
return false;
}
}
既然我们用User获取用户的数据,这样我们需要在Action增加User类型的数据成员,而去掉原来的username和password,重构的代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends ActionSupport {
private User user;
@Override
public String execute() throws Exception {
if(user.login()){
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
在这里页面的数据不再由控制器的username和password数据成员获取,转而有其中的user对象进行封装。所以应该修改login.jsp的提交表单,修改后的结果如下:
<form action="login.action">
Username:<s:textfield name="user.username"/><br>
Password:<s:textfield name="user.password"/><br>
<input type="submit" value="Login"/>
</form>
注意此时提交表单中的文本框名称必须为user.username和user.password,这样所输入的内容会由控制器的user对象获取。
这里可能有一个疑问,就是在控制器中并没有在任何时候创建User对象,那么内容是如何获得的呢?难道不会抛出NullPointerException?此时当请求控制器,并设置user对象的username数据成员时,action依次调用下方法:
user.getUser();
user.setUser(new User());
user.getUser().setUsername("admin");
从上可以看出,首先struts2会尝试获取user对象,如果不存在则执行第二步创建一个新对象,然后将内赋给数据成员
重新部署,运行,所得到的效果和前一个相同。
使用Servlet相关对象
在进行Web编程时,很多时候需要使用Servlet相关对象,例如:HttpServletRequest、HttpServletResponse、HttpSession、ServletContext。我们可以将一些信息存放到session中,然后在需要的时候取出。
在struts1.x的Action中,可以通过HttpServletRequest和HttpServletResponse参数来得到Servlet相关对象,进而使用。那么在struts2种如何获取?
我们可以使用com.opensymphony.xwork2.ActionContext类来完成上述操作。此类的getContext方法可以得到当前Action的上下文,也就是当前Action所处的容器环境,进而得到相关对象。
同时也可以使用org.apache.struts2.ServletActionContext类获得,例如:
HttpServletRequest req=ServletActionContext.getRequest();
下面更改前面的登录操作,在登录成功后,将登录人员的信息保存到session范围中,在index.jsp页面中取出,我们可以重构我们的Action,在重构前,首先新增一个BaseAction,作为所有Action的父类,在其中增加方法获取Servlet相关对象,这样所有的子类都拥有了相应的方法。代码如下:
package com.frank.action;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
public class BaseAction extends ActionSupport {
public HttpServletRequest request(){
return ServletActionContext.getRequest();
}
public HttpServletResponse response(){
return ServletActionContext.getResponse();
}
public ServletContext application(){
return ServletActionContext.getServletContext();
}
public HttpSession session(){
return ServletActionContext.getRequest().getSession();
}
}
然后重构LoginAction,继承自BaseAction,并在登录成功后再session范围保存用户名信息,以便index.jsp读取,重构后代码如下:
package com.frank.action;
import com.opensymphony.xwork2.ActionSupport;
import com.frank.rule.User;
public class LoginAction extends BaseAction {
private User user;
@Override
public String execute() throws Exception {
if(user.login()){
this.session().setAttribute("username", user.getUsername());
return SUCCESS;
}
return INPUT;
}
@Override
public void validate() {
if(user.getUsername()==null||user.getUsername().trim().length()<1){
addFieldError("no.username","must input username");
}
if(user.getPassword()==null||user.getPassword().trim().length()<1){
addFieldError("no.password","must intpu password");
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
在index.jsp中增加读取session中保存内容的代码,如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h1>Login Success!!!</h1>
<br>
<h1>Username:<%=session.getAttribute("username") %></h1>
</body>
</html>
相关文章推荐
- 关于Struts2中Action从表单取值并且存到Web元素中(session)
- Struts2_学习笔记(五)----访问Web元素、include、默认Action、Action总结
- struct2 访问WEB元素(request,session, application......)——分模块配置——默认Action
- 【Struts2复习知识点十二】-web元素request session application等
- struts 在Action中访问web元素(request,session等)
- struts2之Action获取请求参数与web元素
- STRUTS2 ACTION 访问WEB元素的四种方式
- struts2之Action获取请求参数与web元素(四)
- Struts2 Action访问web元素的四种方式
- java web从零单排第七期《struts2》用ActionSupport类验证提交表单
- struts2,jsp的表单中用<input>元素与action进行数据交互
- struts2获取requestd session 等web元素的四种方式
- Struts2访问web元素(Request,Session,Application)的四种方式
- Struts2访问web元素(包括:request,session,application和HttpServletRequest,HttpServletSession, HttpServletContext)的4种方法
- struts2获取web元素(request、session、application)
- Struts2 Action类无法获取web表单数据
- 在Struts2中访问Web页面元素request、response、session、application的四种方法
- STRUTS2 ACTION 访问WEB元素的四种方式
- 关于ActionContext.getContext()取得的值是什么,和struts2如何获取request,session,appliaction作用域
- Struts2之web元素访问与模板包含与默认Action使用