刚开始学习struts2的相关内容,小结一下。
首先说下环境的配置:
1.下载struts2.3.15.1,解压出apps/blank.war,这里面就是一个完整的实例,我们找到struts-2.3.15.1\apps\struts2-blank\WEB-INF\lib,把里面的jar文件都复制到你的web project工程的WebRoot\WEB-INF\lib里面,然后在struts2-blank\WEB-INF\classes里找到struts.xml,复制到src里就行了,这样基本的环境就配置好了。
看下我的:
画了一个struts2的工作流程图:
以一个helloworld的例子来看。
struts2是一个控制流程的指挥者,Client 访问http://a.com/xxx/hello,Client的访问首先被tomcat接手,tomcat从URL中发现Client想访问xxx,那就找到xxx目录,定位到hello前看下xxx/WEB-INF/web.xml,在里面发现了过滤器,贴下web.xml的源码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
既然有过滤器,而且过滤器<url-pattern>/*</url-pattern>,即所有访问都要先经过struts2这个过滤器,那就把Client的request交给struts2filter,它会在struts.xml里依次查找namespace、action,看下struts.xml代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.devMode" value="true" /> <!-- 开发模式 这样的话每次修改都会在浏览器立刻体现,而不用重启服务器 -->
<package name="default" namespace="/" extends="struts-default">
<action name="*">
<result name="success">
/hello.jsp
</result>
</action>
</package>
<include file="example.xml" />
<!-- Add packages here -->
</struts>
这里namespace为/,这个“/”对应xxx/目录,action name为* ,即所有访问都返回它对应result,一般写成
<result>
/hello.jsp
</result>
就可以使访问XXX/目录下所有的请求都返回hello.jsp,不过此时我写成
<result name="success">也可以,因为默认值就是success。
看下结果:
这是最简单的一个过程,中间没有经过action,正在学,学会了再加吧
-------------------------------------------------分割线----------------------------------------------
刚尝试写了一个简单的验证系统,login.jsp填写登陆表单,提交到userlogin这个action,struts.xml将这个请求提交给login.java这个action,并在提交的同时将username password 通过set方法传给action(甚至直接可以访问userlogin?username=123&password=123来传参),action判断用户名密码是否正确,然后将结果返回成一个string返回给xml,xml再根据配置返回对应的jsp。
(除此之外,还可以使用domain model传参,方法是这样:1建立一个user.java的model类,2.在action中不要写username password了,写一个User user = null;和他的setget方法,然后可以通过:userlogin?user.username=123&password=456传参 )
传参方面的知识介绍:
-----------------------细节分割线 开始-----------------------------
三种传参的方式:1.用action属性(get set) 2.用domain model 3.用model driver
传参包含中文的问题:要想传参包含的中文不成为乱码,应该这样:1.提交表单的JSP页面中设置提交方式为POST 2.在struts.xml里增加:
<constant name="struts.i18n.encoding" value="GBK"/> 这句话其实就是把action中的reuqest的字符集设置成了gbk 完毕。
-----------------------细节分割线 结束-----------------------------
login.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Sign On</title>
</head>
<body>
<s:form action="userlogin">
<s:textfield key="username"/>
<s:password key="password" />
<s:submit/>
</s:form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
<constant name="struts.enable.DynamicMethodInvocation" value="false"
/> <constant name="struts.devMode" value="true" /> <package
name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" /> <global-results> <result
name="error">/error.jsp</result> </global-results>
<global-exception-mappings> <exception-mapping
exception="java.lang.Exception" result="error"/>
</global-exception-mappings> <action name="index"> <result
type="redirectAction"> <param name="actionName">HelloWorld</param>
<param name="namespace">/example</param> </result> </action>
</package>
-->
<constant name="struts.devMode" value="true" /> <!-- 开发模式 这样的话每次修改都会在浏览器立刻体现 -->
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index"> <!-- 默认 -->
<result>/hello.jsp</result>
</action>
<action name="userlogin" class="action.login">
<result name="success">
/loginsuccess.jsp
</result>
<result name="error">
/error.jsp
</result>
</action>
</package>
<include file="example.xml" />
<!-- Add packages here -->
</struts>
login.java
package action;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class login extends ActionSupport {
private String username = null;
private String password = null;
String FORWARD = null;
private HttpServletRequest request = ServletActionContext.getRequest(); // 获取request
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 String execute() throws Exception {
request.setAttribute("username", username);
if (username.equals("123")) {
FORWARD = "success";
} else {
FORWARD = "error";
}
return FORWARD;
}
}
loginsuccess.jsp
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<body>
用户:<%=request.getAttribute("username") %>登陆成功. <br>
</body>
</html>
------------------------------------------------继续深入学习--------------------------------------------------
0.struts.xml学习方法
(1)当我们不知道如何配置的时候可以打开struts-2.3.15.1\docs\WW\docs\home.html查询文档
(2)关于常量的默认配置我们可以打开struts2-core-2.3.15.1.jar\org.apache.struts2\default.properties这个文件,里面保存着xml里所有变量的默认属性 比如struts.i18n.encoding 我们可以修改哦
1.sturts.xml的package包配置
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index"> <!-- 默认 -->
<result>/hello.jsp</result>
</action>
<action name="userlogin" class="action.login">
<result name="success">
/loginsuccess.jsp
</result>
<result name="error">
/error.jsp
</result>
</action>
</package>
如上,package有三个属性,name:必须的,包的名字,随便写,默认是default, extends:可选属性,指定包的父包,默认是struts-default,继承了这个包才能用Struts2的核心功能哦,namespace:可选,命名空间,默认是/ ,若为/或空,当无法精确定位到别的namespace时,都将访问这里的action。如果为/123 那么在原来的目录后加/123/即可访问
struts.xml的一些常量
<!-- 该属性指定需要Struts2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 -->
<constant name="struts.action.extension" value="do" />
<!-- 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 -->
<constant name="struts.serve.static.browserCache" value="false" />
<!-- 当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 -->
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 开发模式下使用,这样可以打印出更详细的错误信息 -->
<constant name="struts.devMode" value="true" />
<!-- 默认的视图主题 -->
<constant name="struts.ui.theme" value="simple" />
<!--<constant name="struts.objectFactory" value="spring" />-->
<!--解决乱码 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 指定允许上传的文件最大字节数。默认值是2097152(2M) -->
<constant name="struts.multipart.maxSize" value="10701096"/>
<!-- 设置上传文件的临时文件夹,默认使用javax.servlet.context.tempdir -->
<constant name="struts.multipart.saveDir " value="d:/tmp" />
2.Action类文件
struts2的action不需要继承任何类和接口,比如struts1借用ActionForm获取表单数据,但struts2可以利用setter getter获得。虽然不是必须要实现接口或继承父类,但一般需要继承ActionSupport类或实现Action接口,重写execute()方法,因为action被调用时默认会调用这个方法。
(1)method属性
<action name="userlogin" class="action.login" method="login">
这时struts不再调用默认的execute方法,而是调用指定的login方法。
<action name="user_*" class="action.login" method="{1}">
这个更好用,当请求user_为前缀的action时,都将访问这个action文件,然后将后面的通配符作为方法名去调用,比如请求user_login,则会调用login.java的login方法
(2)action内获取request session的方法
private HttpServletRequest request;
public String execute() throws Exception {
request = ServletActionContext.getRequest();
return "success";
}
3.简单数据验证
流程:login.jsp提交一个含有username的表单给 userlogin.java这个action,action判断用户名不是123时返回一个错误,并跳转回login.jsp
贴代码
login.jsp
<%@ page contentType="text/html; charset=gbk"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Sign On</title>
</head>
<body>
<s:form action="userlogin">
<s:fielderror name="user"/><!-- 这个标签可以用来显示错误信息 -->
用户名<input type="text" name="username"/>
<s:fielderror name="pwd"/><!-- 这个标签可以用来显示错误信息 -->
密码<input type="text" name="password"/>
<input type="submit" value="提交"/>
</s:form>
</body>
</html>
struts.xml
<action name="userlogin" class="action.userlogin">
<result name="loginsuccess">
/loginsuccess.jsp
</result>
<result name="input">
/login.jsp
</result>
</action>
userlogin.java
package action;
import javax.servlet.http.HttpServletRequest;
import model.User;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class userlogin extends ActionSupport {
String username = null;
String password = null;
String FORWARD = null;
private HttpServletRequest request = ServletActionContext.getRequest(); // 获取request
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 String execute() throws Exception {
if (getUsername().equals("123")) {
FORWARD = "loginsuccess";
} else {
this.addFieldError("user", "username error!"); //添加错误信息,前台jsp可以用 <s:fielderror fieldName="user"></s:fielderror>接受并显示
FORWARD = "input";
}
return FORWARD;
}
}
3.2关于现实错误信息的细节:如果使用s:fielderror标签,jsp会为这个错误信息提供一个样式显示,如果jsp页面只想单纯的得到错误信息字符串的话,可以使用<s:property value="errors"/>,我们先在JSP页面中添加<s:debug></s:debug>,打开页面后会看到debug信息,在value stack中可以看到 error 对应的value即为错误信息"{user=[username error!], pwd=[pwd error!]} ",所以我们可以使用<s:property value="user"/>直接取到错误信息的值。另外,这个error是一个MAP,我们可以使用<s:property value="errors.user"/>直接显示[username error!],然后呢,这个信息是被方括号包含的 所以他是一个数组元素,那么我们如果写<s:property value="errors.user[0]"/>就会显示"username error!"
4.拦截器
这部分我是看http://www.blogjava.net/max/archive/2006/12/06/85925.html 学习的,详情看这里吧。
另外 可以通过 HttpServletRequest request = ServletActionContext.getRequest();获取request的参数
4.转换器
当action的参数不是String 比如是Date的时候,我们无法直接给action提交参数(其实我觉得是可以给set方法写代码转换的),就可以使用转换器。
转换器由转换类+properties文件构成,这里模拟一个转换Date的小程序:jsp提交date字符串给action包里的convertTest,DateConvert是转换类,xwork-conversion.properties是全局转换器的配置文件,里面的内容:需要转换的类途径=转换他的类途径,在这里就是:java.util.Date=action.DateConvert。
converttest.jsp
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<html>
<body>
<form action="convertTest" method="get">
<input type="text" name="date">
<input type="submit" value="submit date">
</form>
</body>
</html>
convertTest.java
package action;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class convertTest extends ActionSupport {
Date date = null;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String execute() throws Exception {
System.out.println(getDate());
return "success";
}
}
DateConvert.java
package action;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import ognl.DefaultTypeConverter;
public class DateConvert extends DefaultTypeConverter {
public Object convertValue(Map context, Object value, Class toType) {
System.out.println("转化器被执行");
if (toType == Date.class) {
String[] str = (String[]) value;
Date date = new Date(str[0]);
return date;
} else if (toType == String.class) {
Date date = (Date) value;
return date.toString();
}
return null;
}
}
xwork-conversion.properties 这个文件放到src目录下
xwork-conversion.properties