简介:
最近学习了一下Struts2,我又是一个不愿意背的人,所以写点东西留下来,方便以后自己用到时回忆。
因为我比较喜欢在代码中对程序进行注视,所以乍一看代码感觉会多。
注视当中有容易出错的地方的提醒,也有函数解释,所以会显得很罗嗦。
为了让例子以后也可以正常运行,所以没有做DB操作.好吧,我承认我是因为懒。
涉及到的内容有:
- 通过xml配置文件来实现
- 数据校验validation
- 注解方式的实现
- 响应流程
失败的地方:
jsp 传 list 类型的数据到 action 的方法没有实现。
需要的lib有:
struts2版本:struts-2.3.1.2
源代码:
-
在 web.xml 中添加如下代码。作用是当url地址改变时就扫描struts.xml。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!-- 这里会调用默认地址:/WEB-INF/classes下的struts.xml -->
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 在WEB-INF/classes/struts.xml中
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!--
1. package name: 名字可以随便起
2. namespace: 可删除。在这里jsp的action为"/Login/*.action"。添加原因为区分action
如果删除了的话,那么action为"*.action"即可
3. extends: 继承的父package名称
4. action name:acntio的名字(2.中写的jsp的action中的*部分)
5. class:执行该action的class文件路径
6. result name:action的class返回的结果。根据返回结果跳到不同页面
更加相信内容请看:http://hi.baidu.com/ehols/blog/item/1f15aa444a8fa481b3b7dcec.html
-->
<package name="ASD" namespace="/Login" extends="struts-default">
<action name="login" class="com.action.LoginAction">
<result name="success">/WEB-INF/main.jsp</result>
<result name="fail">/fail.jsp</result>
<!-- input为Struts2自带表单验证validate(本例子中为LoginAction-validation.xml)验证失败后返回值 -->
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
关于这个部分更详细的解释可以看:点击打开链接
3. index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>登陆界面</title>
<!-- 定义CSS,使错误信息以红色进行显示 -->
<style type="text/css">
.label {
font-style: italic;
}
.errorLabel {
font-style: italic;
color: red;
}
.errorMessage {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
请输入以下信息:
<br />
<!-- 在这里不要写成 <s:form action="/Login/login" > 这样写运行时将会报一大堆警告 -->
<s:form name="loginForm" action="login" namespace="/Login" method="post">
<s:textfield name="id" label="用户名" />
<s:password name="pwd" label="密码" />
<s:submit value="登陆" />
<s:reset name="重置"></s:reset>
</s:form>
</body>
</html>
4. 在com.action.LoginAction中
package com.action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.entity.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
public class LoginAction extends ActionSupport implements Preparable{
private static final long serialVersionUID = 8740491047560899431L;
private String id; //对应页面中的s:textfield name
private String pwd; //对应页面中的s:textfield name
ArrayList<User> userList; //所有的用户信息
//该Action的业务的执行函数
public String execute() throws Exception
{
HttpServletRequest request = ServletActionContext.getRequest();
if(id.equals("mizhiwu") &&
pwd.equals("123")){
String str = "2012-2-20";
request.setAttribute("date", str);
return "success";
}
else{
return "fail";
}
}
//自定义的特殊校验类在validate.xml中写不了的话就在这写,自动加载
//validate.xml讲解请看下面
public void validate(){
if(!id.equals("mizhiwu")){
this.addFieldError("id","用户名请输入 mizhiwu");
}
if(!pwd.equals("123")){
this.addFieldError("pwd","密码请输入 123");
}
}
//在表单验证(validate)中需要用到get方法
public String getId() {
return id;
}
public String getPwd() {
return pwd;
}
//jsp页面跳到这里后,set方法首先自动调用,加载jsp页面的值
//即使标签为<input type="text" name="id" >标签的也可以通过这样获得
public void setId(String id) {
this.id = id;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
//可以使该Action跳转后的页面可以通过<s:iterator value="userList" var="var">直接获得
public ArrayList<User> getUserList() {
return userList;
}
public void setUserList(ArrayList<User> userList) {
this.userList = userList;
}
//继承Preparable后必须实现的函数
//prepare函数先于validate实现
//实现理由是:保存原数据,有益于用户体验
//不适用的后果:如果validation验证失败,那么返回登陆页面时,
// 之前的用户名,密码等数据将全部丢失,用户必须重新填写
//函数内要做的内容:首先get数据,并重新set一下。并把页面加载时都要做的事放在该函数中
public void prepare() throws Exception {
//该页面加载时总是要做的事--获得所有用户信息(模拟)
ArrayList<User> userList = new ArrayList<User>();
User user1 = new User("id1","123");
User user2 = new User("id2","123");
userList.add(user1);
userList.add(user2);
setUserList(userList);
//get数据
String tempId = getId();
//set数据,以免validation返回时数据丢失
setId(tempId);
}
}
5. 在com.action下,也就是与LoginAction同一个位置中,新建LoginAction-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<!-- 详细部分请看:http://hi.baidu.com/cnkarl/blog/item/389d5a176c9e2412962b43a5.html -->
<field name="id">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>请填写用户名</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">4</param>
<param name="maxLength">10</param>
<message>用户名长度应在4到10个字符间</message>
</field-validator>
</field>
<field name="pwd">
<field-validator type="requiredstring">
<message>请填写密码</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">2</param>
<param name="maxLength">10</param>
<message>为了您账号的安全,请设置2个字母以上的密码(最长可设置10个字母)</message>
</field-validator>
</field>
</validators>
这是Struts2自带的validation.起好名字后将会自动调用。
正确的位置是:需要验证的Action类同一个位置。
正确的名字是:Action名字-validation.xml。
更详细的看:点击打开链接
错误提示效果:
6. WEB-INF/main.jsp中
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>主界面</title>
<style type="text/css">
.label {
font-style: italic;
}
.errorLabel {
font-style: italic;
color: red;
}
.errorMessage {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
<!-- 在跳到该页面前的action(LoginAction)中,有get,set方法,就可以以"${变量名}"形式获得 -->
Hello ${id}
<br>
<br>
输出所有用户(用 s:iterator):
<br>
<!-- 获得action传来的值并利用s:iterator来输出 -->
<s:iterator value="userList" var="var">
<li>用户名:<s:property value="#var.id" /></li>
<li>密码:<s:property value="#var.pwd" /></li>
<br>
</s:iterator>
<s:form name="mainList" action="addOneUser" namespace="/AboutUser"
method="post">
<!-- 下面这样是错误的! -->
<!-- <s:hidden name="hidUserList" value="%{userList}"></s:hidden> -->
<!-- 通过hidden的传值 -->
<s:hidden name="hidID" value="%{id}"></s:hidden>
<s:textfield name="nowTime" label="当前时间" value="%{#request.date}" />
当前登录用户:<input type="text" name="test1"
value='<s:property value="id" />' />
<s:submit value="添加用户" />
</s:form>
</body>
</html>
OK,如果只是想简单了解一下的话,那么到这里就可以了。你可以尝试着运行了。
到这里我们实现了最基础的部分(用户登陆以及显示主页面信息操作。其中包括传值,跳转),而且附带个页面验证功能。
到这部分,我们需要注意的一点就是validation验证失败后返回的部分。
也就是LoginAction-validation.xml验证失败后会返回登陆页面,但默认情况下,我们之前输入的用户名等数据将全部丢失。
换句话说用户一旦输入不符合规范,那么倒霉的用户就需要重新全部填写信息,重新登陆。
如果登陆不恐怖的话,想想如果这是一个申请页面,就因为身份证号少输入一位,你就要重新填写一大堆的数据,重新申请。
为了避免这种情况,所以我们在LoginAction中实现Preparable接口的prepare函数,在该函数中把我们想要保存的值get,set一下。
也许是我刚学习的原因吧,感觉Struts2的validation很鸡肋。在这里只是学习一下。
实际应用中觉得还是使用ajax会更好更容易一些。ajax部分我会在Spring MVC 部分进行说明。
接下来我们通过annotation(注解)的方式来实现数据校验和Action管理。抛弃繁琐的xml设置。
7. 在com.action.AddUserAction中
package com.action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import com.entity.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.validator.annotations.Validations;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork2.validator.annotations.ValidatorType;
//注解方式的数据校验
@Validations(requiredStrings ={
@RequiredStringValidator(type = ValidatorType.FIELD,
fieldName = "nowTime", message = "当前时间不能为空")})
//@InterceptorRefs({
// @InterceptorRef("prepare"),
// //@InterceptorRefs("defaultStack")
//})
@Namespace("/AboutUser") //指定名称空间
public class AddUserAction extends ActionSupport implements Preparable{
private static final long serialVersionUID = -3354842689160304136L;
private String nowTime;
private String hidID;
ArrayList<User> userList; //所有的用户信息
HttpServletRequest request = ServletActionContext.getRequest();
//注解方式的Action
@Action(value = "/addOneUser", results = {
@Result(name = "success", location = "/WEB-INF/addUser.jsp"),
@Result(name = "fail", location = "../../fail.jsp"),
@Result(name = "input",location = "../main.jsp")
}
)
public String execute()
{
System.out.println("******************");
System.out.println(hidID);
System.out.println("******************");
return "success";
}
public String getHidID() {
return hidID;
}
public void setHidID(String hidID) {
this.hidID = hidID;
}
public String getNowTime() {
return nowTime;
}
public void setNowTime(String nowTime) {
this.nowTime = nowTime;
}
public ArrayList<User> getUserList() {
return userList;
}
public void setUserList(ArrayList<User> userList) {
this.userList = userList;
}
public void prepare() throws Exception {
//无奈的办法。。。。。不然不填写当前日期的话,validation验证失败后,main.jsp页面将没有所有用户信息。
ArrayList<User> userList = new ArrayList<User>();
User user1 = new User("id1","123");
User user2 = new User("id2","123");
userList.add(user1);
userList.add(user2);
setUserList(userList);
}
}
如果想验证一下这个注解方式的数据校验的话,只需要将当前时间框的数据去掉就可以了。
8. 在WEB-INF/addUser.jsp中
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>这是注解方式实现的</title>
</head>
<body>
这是注解方式实现的<br>
</body>
</html>
至此,所有代码全部完成。
在这里可以看出,如果我们通过注解的方式来编写代码的话,我们可以不用写struts.xml,不用写validation.xml。非常的方便。
美中不足的是我在这里没有实现当添加用户时校验失败,返回到main.jsp的话,我唯一的办法就是再一次的连接数据库(模拟),
然后取出所有用户信息,进行显示。否则main.jsp显示所有用户信息界面中,将没有任何数据。
正常的话应该是AddUserAction中的prepare()函数获得main.jsp页面中的userList后重新set一下。
可是我无法实现jsp传list属性值到action当中。
如果有哪位能告诉我解决方法的话在下将感激不尽。
值得说明的是,在Struts2中页面间传值通常用<s:hidden>标签传递数据。
源程序的话大家可以到: 点击打开链接 下载。
导入该程序的用户需要重新导入servlet-api包(在Tomcat的安装路径下的lib文件夹下面有)。
呼~,下面说一下响应流程。与其说是响应流程,不如说是java怎么找到的正确代码执行方式。反正我也不知道叫什么才确切。
响应流程:
- 首先是Index.jsp页面。并当点击登录按钮时发送“/Login/login”地址。
- 这时首先启动的是web.xml。
- web.xml通过<filter-name>struts2</filter-name> 找到了/WEB-INF/classes下的struts.xml。
- 在struts.xml中在第17行中找到了"/Login",在第18行找到了"login",并且找到了处理该Action的class地址“com.action.LoginAction”。
- 在LoginAction.class中执行了prepare()函数和validation校验。如果没有问题执行了execute()函数,执行业务逻辑部分。
- 之后LoginAction.class返回结果(如"success")。
- 返回到struts.xml中,在19行找到了对应的返回结果对应的页面(/WEB-INF/main.jsp).
- 显示/WEB-INF/main.jsp页面。
大功告成~~~~