struts2框架详解
struts2框架(1)---struts2入门
struts2框架
如果你之前在MVC模式的时候一直都是通过servlet,获取和返回数据,那么现在开始学习struts2框架,
Struts是一个实现MVC设计模式的优秀的框架。它的许多优点我就不说了。
我用自己做的一张图说明servlet和struts2的区别。
写一个最基本的开发步骤,完成开发。
(1)创建WEB 工程
(2)导入必要jar包
(3) 编写JSP 页面
(4)编写Action 服务器端处理逻辑
(5)进行框架配置web.xml、struts.xml
(6)运行测试
(1)创建WEB 工程
这步还是很正常一样,创建一个普通web工程。如图:
(2)导入必要jar包
首先我要告诉你到哪里去下载这个框架:在apache官网,你百度struts2下载就可以找到了。
Struts运行必要jar包介绍:
开发中为了方便导入,可以使用app/struts2-blank.war 携带jar包
(3) 编写JSP 页面
在webRoot下新建一个Demo文件,网页先访问start.jsp之后通过框架返回到result页面
start.jsp界面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> </head> <body> <h1>请求发起的页面</h1> <!-- 发起一个请求 访问Struts2框架 --> <!-- Struts2请求 默认是以.action结尾 --> <a href="${pageContext.request.contextPath }/hello.action">访问Struts2入门程序</a> </body> </html>
result.jsp界面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> </head> <body> <h1>处理完成的结果页面</h1> </body> </html>
(4)编写Action 服务器端处理逻辑
这里就是通过java创建一个类,该类可以说是action最普通的一个类
1 package com.yudian.struts; 2 public class HelloAction { 3 public String execute() throws Exception{ //这里取execute代表默认执行这个方法 4 System.out.println("我是执行的内容..."); 5 return "excutesuccess"; //有返回值,我们用来跳转页面 6 } 7 }
(5)进行框架配置web.xml、struts.xml
配置文件才是核心关键,先配置web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <!-- 配置Struts2的前端控制器 --><!--filter-class里面很关键,固定 --> 9 <filter> 10 <filter-name>struts2</filter-name> 11 <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 12 </filter> 13 <filter-mapping> 14 <filter-name>struts2</filter-name> 15 <url-pattern>/*</url-pattern> 16 </filter-mapping> 17 18 19 <welcome-file-list> 20 <welcome-file>index.jsp</welcome-file> 21 </welcome-file-list> 22 </web-app>
在配置struts.xml,注意了这个是放在src下面而不是包下面
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 6 <struts> 7 <package name="default" extends="struts-default"> 8 <!-- 3.默认Action 和Action的默认处理类 --> 9 <!-- 1.初步认识Struts2 --><!-- 这里hello一定要和jsp中hello。action一致才能找到 --> 10 <action name="hello" class="com.yudian.struts.HelloAction"> 11 <result name="excutesuccess">/demo/result.jsp</result> 12 </action> <!-- result代表如果返回值为 excutesuccess则跳转页面--> 13 </package> 14 </struts>
(6)运行测试
先通过浏览器访问start界面:
当点击:访问Struts2入门程序连接直接跳转到了result.jsp
运行结果:
这上面是一个最基本的struts框架的运用,很简单,主要是供大家理解,关于每一个细节我会在接下面慢慢补充.
欢迎大家的留言给出指点意见,谢谢!
Struts2系列笔记(2)---struts.XML
Struts2.xml
本篇博客主要讲struts.xml中package下的标签和标签属性,主要分以下四个部分说明:
(1)action的配置基本属性
(2)同一个Action类中不同方法满足不同的action逻辑
(3)通配符解决多业务问题
(4)配置处理结果:
(1)action的配置基本属性
1 <!--首先声明本片文章基本还是参考http://www.cnblogs.com/Nouno/p/5683447.html的博客,特此说明--> 2 <?xml version="1.0" encoding="UTF-8"?> 3 <!DOCTYPE struts PUBLIC 4 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 5 "http://struts.apache.org/dtds/struts-2.3.dtd"> 6 <struts> 7 <!-- /primer/helloWorldAction.action 8 package:包 9 * name:包名,唯一的,必选项 10 * namespace:命名空间,唯一的,相当于房间号。可选项,省略情况下是"/"。页面中请求连接的前半部分 11 * extends:继承 12 * extends="struts-default":struts2框架底层提供的核心包struts2-core-2.3.3.jar下的struts-default.xml文件 13 * 为什么要继承这个struts-default.xml文件? 14 * 因为struts2框架底层提供的struts-default.xml声明了所有的拦截器和拦截器栈, 15 知道在struts2框架运行时执行struts-default.xml文件中的拦截器栈。 16 * 如果不继承struts-default.xml文件,就没有办法使用struts2框架提供的所有拦截器 17 --> 18 <package name="primer" namespace="/" extends="struts-default"> 19 20 <!-- 21 如果找不到对应的action名的时候,配置默认要执行的action 22 * name:指定action的名称 23 --> 24 <default-action-ref name="error"></default-action-ref>
25 27 <action name="error" class="com.yyc.struts.action.ErrorAction"> 28 <result name="error">/error.jsp</result> 29 </action> 30 <!-- 31 action: 32 * name:对应页面中请求连接的后面半部分,这里表示jsp请求链接为hello.action才会和它匹配 33 * class:对应要执行的类的完整路径 ,表示Action类的完整路径,相当于之前的servlet类 34 *method:对应的class类中要执行的方法,默认执行method="execute()" 35 --> 36 <action name="hello" class="cn.yht.primer.HelloWorldAction" method="execute()"> 37 <!-- 38 result:结果类型 ,可以用来把Action类处理好的数据跳转到某界面 39 * name:对应的是执行的类的方法的返回值 40 public String execute() throws Exception { 41 System.out.println("HelloWorldAction ************* execute()"); 42 return "success"; 43 } 44 * 默认判断name="success",后半部分的文本内容:要转向到的页面 45 --> 46 <result name="success">/primer/success.jsp</result> 47 </action> 48 <!-- 49 没有为action指定class 50 * 在struts2框架底层的struts-default.xml文件中,配置了默认执行的类 51 com.opensymphony.xwork2.ActionSupport 52 public String execute() throws Exception { 53 return SUCCESS; 54 } 55 * 实际上,默认执行的是底层提供的ActionSupport类的execute()方法 56 * result结果类型,默认是根据struts2框架底层提供的ActionSupport类的execute()方法返回值,进行跳转 57 --> 58 <action name="actionNoClass"> 59 <result name="success">/primer/success.jsp</result> 60 </action> 61 </package> 62 </struts>
(2)同一个Action类中不同方法满足不同的action逻辑
1 <!--这个Action中有两个方法 2 public class ProductAction extends ActionSupport { 3 public String add(){ 4 System.out.println("添加商品"); 5 return NONE; 6 } 7 public String del(){ 8 System.out.println("删除商品"); 9 return NONE; 10 } 11 }--> 12 13 <!-- 多个业务需求 --> 14 <action name="addBook" class="com.guigu.struts.action.BookAction" method="add"></action> 15 <action name="delBook" class="com.guigu.struts.action.BookAction" method="del"></action> 16 <!--这样确实能够实现一个Action类中的不同方法,都能被调用 17 但是你也许会注意到,每调用一个方法都需要配置action-->
(3)通配符解决多业务问题
1 <!--这里是jsp文件 2 <h1>客户管理</h1> 3 <a href="${pageContext.request.contextPath }/customer_add">添加客户</a><br/> 4 <a href="${pageContext.request.contextPath }/customer_del">删除客户</a><br/> 5 <a href="${pageContext.request.contextPath }/customer_edit">修改客户</a><br/> 6 <a href="${pageContext.request.contextPath }/customer_find">查询客户</a><br/> 7 --> 8 <!-- 使用通配符解决多业务问题 --> 9 <!-- method 属性{1}是取第一个* ,这样就只需要写一个action就可以了,我们只要在Action类中写好相对应的方法即可--> 10 <action name="customer_*" class="com.guigu.struts.action.CustomerAction" method="{1}"> 11 <result >/demo1/{1}.jsp</result> 12 </action>
(4)配置处理结果:
Struts2的Action处理用户请求结束后,返回一个普通字符串-逻辑视图名,必须在struts.xml文件中完成逻辑视图和物理视图资源的映射,才可让系统转到实际的视图资源。
Struts2通过在struts.xml文件中使用<result …/>元素来配置结果。Struts2提供了两种结果。
a.局部结果:将<result …/>作为<action …>元素的子元素配置。
b.全局结果:将<result …/>作为<global-results …>元素的子元素配置。
在package元素中配置<global-results>子元素:
<!--全局result(global-results) 有很多时候一个<result>可供很多<action>使用,这时可以使用<global-results>标签来定义全局的<result>l。执行顺序:当一个Action返回的String没有相应的<result>与之对应,Struts2就会查找全局的<result>。--> <global-results> <result name="error">/Error.jsp</result> <result name="invalid.token">/Error.jsp</result> <result name="login" type="redirect-action">Logon!input</result> </global-results>
欢迎大家留言指点!
Struts2框架(3)---Action类的3种书写方式
Action类的3种书写方式
本文主要写有关写Action类的3种书写方式:
(1)第一种 Action可以是POJO (简单模型对象) 不需要继承任何父类 也不需要实现任何接口
(2)实现Action接口
(3)继承ActionSupport(推荐)
那我们先来书写第一种:
(1)第一种 Action可以是POJO (简单模型对象) 不需要继承任何父类 也不需要实现任何接口
1 //这里其实就是一个普通的类,类里面的方法可以任意写,如果写execute()方法那就代表默认执行它 2 public class RequestAction1 { 3 //提供满足条件的方法 excute方法 4 //public 范围的 带有String返回值的 无参的方法 5 public String execute(){ 6 System.out.println("测试方式一"); 7 return null;//null表示不进行跳转 8 } 9 }
(2)实现Action接口
1 import com.opensymphony.xwork2.Action; 2 public class RequestAction2 implements Action{ 3 4 public String execute() throws Exception { 5 System.out.println("方式二 实现Action接口 成功执行...."); 6 return SUCCESS; 7 } 8 } 9 /** 10 * Action接口中一共有5个五种逻辑视图 和一个方法分别如些: 11 * public abstract interface com.opensymphony.xwork2.Action { 12 数据处理成功(成功的跳转页面) 13 public static final java.lang.String SUCCESS = "success"; 14 页面不进行跳转 return null 15 public static final java.lang.String NONE = "none"; 16 数据处理发送错误(错误页面) 17 public static final java.lang.String ERROR = "error"; 18 用户处理数据 数据有误 用于表单的校验 19 public static final java.lang.String INPUT = "input"; 20 主要是权限认证 21 public static final java.lang.String LOGIN = "login"; 22 23 public abstract java.lang.String execute() throws java.lang.Exception; 24 } 25 */
(3)继承ActionSupport(推荐)
1 import com.opensymphony.xwork2.Action; 2 import com.opensymphony.xwork2.ActionSupport; 3 //为什么推荐ActionSupport,在Action中如果使用基础ActionSupport的方式 可以使用表单的校验 错误信息的设置 和国际化信息 三个重要的功能。 4 public class RequestAction3 extends ActionSupport { 5 @Override 6 public String execute() throws Exception { 7 System.out.println("方式三 继承ActionSupport完成 书写"); 8 return super.execute();//返回SUCCESS 9 } 10 } 11 /**ActionSupport类的特点,点进去发现它实现了许多的接口 12 * public class ActionSupport implements Action, Validateable, 13 * ValidationAware, TextProvider, LocaleProvider, Serializable 14 * 这么多接口说明它不简单 15 * 16 */
关于action类的创建我就说这么多!请大家多指点!
Struts2框架(4)---Action类访问servlet
Action类访问servlet
Action类有三种方式servlet:
(1)间接的方式访问Servlet API ---使用ActionContext对象
(2) 实现接口,访问Action时完成注入
(3)直接通过ServletActionContext获得Servlet的API
下面我来讲第一种:
(1)间接的方式访问Servlet API ---使用ActionContext对象
Struts2中提供了一个ActionContext类(当前Action的上下文对象),通过这个类可以访问Servlet API。下面是该类中提供的几个常用方法:
1.public static ActionContext getContext() :获得当前Action的ActionContext实例。 |
2.public Object get(Object key) :此方法类似于调用HttpServletRequest的getAttribute(String name)方法。 |
3.public void put(Object key, Object value) :此方法类似于调用HttpServletRequest 的setAttribute(String name, Object o)。 |
4. public Map getParameters() :获取所有的请求参数。类似于调用HttpServletRequest对象的getParameterMap() 方法。 |
5. public Map getSession() :返回一个Map对象,该Map对象模拟了HttpSession实例。 |
6. public void setSession(Map session) : 直接传入一个Map实例,将该Map实例里的key-value对转换成session的属性名-属性值对。 |
7. public Map getApplication() :返回一个Map对象,该对象模拟了该应用的ServletContext实例。 |
8. public void setApplication(Map application) :直接传入一个Map实例,将该Map实例里 的key-value对转换成application的属性名- 属性值对。 |
1 import java.util.Map 2 import com.opensymphony.xwork2.ActionContext; 3 import com.opensymphony.xwork2.ActionSupport; 4 public class LoginAction1 extends ActionSupport{ 5 6 public String login() throws Exception{ 7 //获取ActionContext 8 ActionContext actionContext =ActionContext.getContext(); 9 //1.获取表单的请求参数 10 Map<String, Object> parameters=actionContext.getParameters(); 11 //因为用户名username可能有多个,所以返回数组 12 String [] values =(String[]) parameters.get("username"); 13 System.out.println("用户名是:"+values[0]); 14 15 //2.存取request 的Attribute 16 actionContext.put("company", "雨点的名字"); //相当于request.setAttribute("",""); 17 System.out.println(actionContext.get("company")); 18 19 //3.存取session 的Attribute 20 Map<String, Object> sessionMap=actionContext.getSession(); 21 sessionMap.put("age", 11);//相当于session.setAttribute("",""); 22 System.out.println(sessionMap.get("age")); 23 24 //4.存取application的Attribute 25 Map<String, Object> applicationMap=actionContext.getApplication(); 26 applicationMap.put("info", "下周考试第二阶段"); 27 System.out.println(applicationMap.get("info")); 28 return SUCCESS; 29 } 30 }
(2) 实现接口,访问Action时完成注入
如果是实现结构注入一般需要实现3个接口
(1)ServletContextAware: 实现此接口的Action可直接访问Web应用的ServletContext实例; |
(2)ServletRequestAware: 实现此接口的Action可直接访问Web应用的HttpServletRequest实例; |
(3)ServletResponseAware: 实现此接口的Action可直接访问Web应用的HttpServletResponset实例 |
1 import java.util.Map; 2 3 import javax.servlet.ServletContext; 4 import javax.servlet.ServletResponse; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import org.apache.struts2.interceptor.RequestAware; 8 import org.apache.struts2.interceptor.ServletRequestAware; 9 import org.apache.struts2.interceptor.ServletResponseAware; 10 import org.apache.struts2.util.ServletContextAware; 11 12 import com.opensymphony.xwork2.ActionContext; 13 import com.opensymphony.xwork2.ActionSupport; 14 15 public class LoginAction2 extends ActionSupport implements ServletRequestAware, 16 ServletContextAware,ServletResponseAware { 17 18 private HttpServletRequest request; 19 20 private ServletContext context; 21 22 private HttpServletResponse response; 23 24 public String login() throws Exception{ 25 //1.获取表单的请求参数 26 System.out.println(request.getParameter("username")); 27 28 //2.存取request 的Attribute 29 request.setAttribute("company","hzgg" ); 30 31 //3.存取session 的Attribute 32 request.getSession().setAttribute("age", 50); 33 34 //4.存取application的Attribute 35 context.setAttribute("info", "今天下午你们可以出去玩"); 36 37 return SUCCESS; 38 39 } 40 //实现ServletRequestAware接口必须实现的方法 41 public void setServletRequest(HttpServletRequest request) { 42 this.request=request; 43 } 44 //实现ServletContextAware接口必须实现的方法 45 public void setServletContext(ServletContext context) { 46 this.context=context; 47 } 48 //实现ServletResponseAware接口必须实现的方法 49 public void setServletResponse(HttpServletResponse response) { 50 this.response=response; 51 } 52 53 }
(3)使用ServletActionContext工具类访问Servlet API
在ServletActionContext工具类中常用的几个方法(都是静态方法):
(1)PageContext getPageContext(): 取得应用的PageContext对象; |
(2)HttpServletRequest getRequest(): 取得该应用的HttpServletRequest对象; |
(3)HttpServletRequest getResponse(): 取得该应用的HttpServletResponse对象; |
(4)ServletContext getServletContext(): 取得该应用的ServletContext对象。 |
1 import org.apache.struts2.ServletActionContext; 2 import com.opensymphony.xwork2.ActionSupport; 3 4 public class LoginAction3 extends ActionSupport { 5 6 public String login() throws Exception { 7 // 1.获取表单的请求参数 8 String username= ServletActionContext.getRequest().getParameter("username"); 9 System.out.println(username); 10 11 // 2.存取request 的Attribute 12 ServletActionContext.getRequest().setAttribute("company", "haha"); 13 14 // 3.存取session 的Attribute 15 ServletActionContext.getRequest().getSession().setAttribute("age", 40); 16 17 // 4.存取application的Attribute 18 ServletActionContext.getServletContext().setAttribute("info", "今天下课你们可以约会去了"); 19 20 return SUCCESS; 21 } 22 }
下面我来写一个用第三种方法实现访问servlet,从jsp到struts.xml在到Action类,最后从页面显示结果供大家学习:
jsp界面:
start.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> </head> <body> <form action="${pageContext.request.contextPath }/hello.action"> 姓名:<input type="text"> <input type="submit" value="提交"> </form> </body> </html>
struts.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <package name="default" extends="struts-default"> 7 <action name="hello" class="com.guigu.struts.action2.LoginAction3" method="login"> 8 <result>/result.jsp</result> 9 </action> 10 </package> 11 </struts>
result.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> </head> <body> <p>${company}</p> <p>${age}</p> <p>${info}</p> </body> </html>
运行结果如下:
当点击提交的时候
发现数据已经从Action类中转发到了界面
这篇文章就讲到这里,欢迎大家指点和点评!
Struts2框架(5)---result结果集
result结果集
上一篇文章主要讲Struts2框架(4)---Action类访问servlet这篇主要讲result结果集
在Struts.xml中的result元素指的是:指定动作类的动作方法执行完后的结果视图.
(1)局部结果和全局结果
他有两个属性:
name:字符串,与动作方法返回的值一致。默认是success
type:指定处理结果的结果类型的别名。默认值是dispatcher
首先处理结果分为两种,一种是局部结果一种是全局结果。
局部结果:
<action name="login" class="com.study.struts.action2.LoginAction" method="login"> <!--在action内配置的是针对某个Action起作用的局部的配置 --> <result name="success" >/demo2/result.jsp</result> </action>
全局结果:
<!--全局结果视图:包中所有的action都能使用同一个视图 --> <global-results> <!-- <result name="success">/index.jsp</result> --> <!-- a.默认的结果集类型 --> <result name="error" type="dispatcher">/error.jsp</result> <!-- b.转发到另外一个Action --> <!-- <result name="success" type="chain">hello</result> --> <!-- c.重定向到jsp页面 --> <!-- <result name="success" type="redirect">/index.jsp</result> --> <!-- d.重定向到action --> <!-- <result name="success" type="redirectAction">hello</result> --> </global-results>
这里同时要思考一个问题,如果你返回的是success,但在全局和局部都配置了,那么会执行哪个呢?
按照规则,先看局部变量是否配置,配置了就执行局部变量的,而且一般成功的结果集不会配置成全局的,只有在错误(error)的时候可能配置全局
(2)结果类型
在struts-default.xml 配置常用结果类型有10种:
当然在我们实际开发中运用的比较多的也就4.5种,这里我就写4种
举例:
1 <action name="main"> 2 <result type="dispatcher">/main.jsp</result> 3 </action> 4 5 <action name="main2"> 6 <result type="redirect">/main2.jsp</result> 7 </action> 8 9 <action name="main3"> 10 <result type="chain">main3</result> 11 </action> 12 13 <action name="main4"> 14 <result type="redirectAction">main4</result> 15 </action>
a) dispatcher(默认) forward到一个JSP或者HTML或者其他结果页面,不能是Action
请求转发,底层调用RequestDispatcher的forward() 方法,dispatcher是result的type属性默认值,通常用于转向一个JSP。
b) redirect 重定向到结果视图 重定向到一个URL
重定向,新页面无法显示Action中的数据,因为底层调用 response.sendRedirect("")方法,无法共享请求范围内的数据。
c) chain 服务器forward(转发)到一个另一个Action
将action的带着原来的状态请求转发到新的action,两个action共享一个ActionContext,actionName指定转向的新的Action的名字,method指定转向哪个方法,
namespace指定新的Action的名称空间,不写表示与原Action在相同的名称空间;
d) redirectAction 重定向到另外一个Action
重定向到另一个Action,参数与chain用法相同,允许将原Action中的属性指定新名称带入新Action中,可以在Result标签中添加 <param name=”b”>${a} </param>,
这表示原Action中的变量a的值被转给b,下一个Action可以在值栈中使用b来操作
(3)重定向和转发的区别?
1 请求转发只能将请求转发给同一个WEB应用中的组件,而重定向还可以重新定向到同一站点不同应用程序中的资源,甚至可以定向到一绝对的URL。
2 重定向可以看见目标页面的URL,转发只能看见第一次访问的页面URL,以后的工作都是有服务器来做的。
3 请求响应调用者和被调用者之间共享相同的request对象和response对象,重定向调用者和被调用者属于两个独立访问请求和响应过程。
4 重定向跳转后必须加上return,要不然页面虽然跳转了,但是还会执行跳转后面的语句,转发是执行了跳转页面,下面的代码就不会在执行了。
因为重定向实际是发送第二个请求,故请求中的东西也就不会出现在第二个请求里面了
也就是说重定向是不共享request的东西,重定向后的页面中无法接收request里的东西
redirect是在处理完当前Action之后,重定向到另外一个实际的物理资源
redirectAction也是重定向,但它重定向到的是另外一个Action
(5)思考,在我们实际开发中是么时候使用重定向什么时候转发?
我个人观点:就是你在request作用域进行相关操作后,需要从数据库返回进行回显的话,比如说你在点击修改的时候就需要把信息回显,这就建议转发,因为用重定向是无法得到回显数据
还有你要跳转到外部网站,比如www.baidu.com,那你就不能用转发,就指定用重定向,这个上面第一点就说了。
本文章就讲到到这里,如果哪里有不足,或者可以修改的更好,欢迎留言指出。
Struts框架(6)---action接收请求参数
action接收请求参数
在web开发中,去接收请求参数来获得表单信息非常的常见,自己也总结整理了有关Struts2通过action接收请求参数的几种方法。
Struts2 提供三种数据封装的方式:
(1) Action 本身作为model对象,通过成员setter封装
(2) 创建独立model对象,页面通过ognl表达式封装
(3) 使用ModelDriven接口,对请求数据进行封装(推荐)
下面我们来讲解第一种:
(1) Action类本身作为model对象通过成员的setter方法封装(属性驱动)
setXxx()的xxx必须与请求的参数名一样。就是指和form表单中的name对应的属性要一致
action类的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import java.util.Arrays; import com.ssh.struts2.model.User; import com.opensymphony.xwork2.ActionSupport; /* * 通过这种方法最简单,但也有缺点如果要把数据封装到model对象中然后传递给业务层和数据层 * 还需要单独定义model对象进行传递数据 */ public class RegisterAction1 extends ActionSupport { private String username; private String [] hobby; @Override public String execute() throws Exception { //获取表单的数据 System.out.println( "用户名是:" +username); System.out.println( "兴趣爱好是:" +Arrays.toString(hobby)); return null ; } //这里必须提供set方法,get方法可有可无 public void setUsername(String username) { this .username = username; } public void setHobby(String[] hobby) { this .hobby = hobby; } } /*当你在界面中用户名输入:zhangsan,兴趣爱好选择:体育和读书那么运行结果如下: * 用户名是:zhangsan * 兴趣爱好是:[sport, read] */ |
struts.xml
1
2
3
4
5
6
7
8
9
10
|
<? 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 > < package name="default" extends="struts-default"> < action name="register1" class="com.ssh.struts2.action.RegisterAction1"> </ action > </ package > </ struts > |
register.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> < html > < head > </ head > < body > < h4 >注册表单1 </ h4 > < form action="${pageContext.request.contextPath }/register1.action" method="post"> 用户名:< input type="text" name="username">< br /> 爱好:< input type="checkbox" name="hobby" value="sport">体育 < input type="checkbox" name="hobby" value="music">音乐 < input type="checkbox" name="hobby" value="read">读书 < br /> < input type="submit" value="注册"> </ form > </ body > </ html > |
网页:
(2) 创建独立model对象,页面通过ognl表达式封装
该方法首先要创建一个专门的领域对象进行封装
User领域对象
import java.util.Arrays; public class User { private String username; private String [] hobby; //为这两个常量提供set和get方法和toString方法
Action类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import com.ssh.struts2.model.User; import com.opensymphony.xwork2.ActionSupport; public class RegisterAction2 extends ActionSupport{ //直接定义model对象 private User user; @Override public String execute() throws Exception { System.out.println( "user:" +user); return NONE; } /* * 必须提供get方法 * 封装第一个参数 创建一个新的User对象 然后把username属性封装到这个创建的user对象中 User user =new User();user.setUserName(""); * 封装第二个参数 已经存在user对象 User user =getUser(); user.setPassword("); */ public User getUser() { return user; } public void setUser(User user) { this .user = user; } } /* * 如果jsp界面输入:用户名:aa 兴趣爱好:体育读书 * 后台输出:user:User [username=aa, hobby=[sport, music]] */ |
register.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <html> 3 <head> 4 </head> 5 <body> 6 <!-- 用ognl表达式要注意的一点就是,标签的属性name在取名字的时候是:领域对象.属性 7 user.username这里user是具体的对象,username是领域对象的属性--> 8 <h4>注册表单1 </h4> 9 <form action="${pageContext.request.contextPath }/register2.action" method="post"> 10 用户名:<input type="text" name="user.username"><br/> 11 爱好:<input type="checkbox" name="user.hobby" value="sport">体育 12 <input type="checkbox" name="user.hobby" value="music">音乐 13 <input type="checkbox" name="user.hobby" value="read">读书 <br/> 14 <input type="submit" value="注册"> 15 </form> 16 </body> 17 </html>
说明:struts2首先通过反射技术调用User的默认构造器创建User对象,然后通过反射技术调用User中与请求参数同名的属性的setter方法来获取请求参数值。在这里需要注意的一点是:User对象一定要有默认的构造器。
采用复合类型接收请求参数的好处,可以减少action中的setter和getter方法,同时可以把相应的属性组合成一个类,这样使代码更好清晰,代码有更好的结构。
(3)使用ModelDriven接口,对请求数据进行封装
第三种方法比较方便,和方法(1)不同在于它也要先创建一个领域对象类进行对象的封装。其它和方法(1)一样
Action类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import com.ssh.struts2.model.User; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; //实现ModelDriven<User>接口 public class RegisterAction3 extends ActionSupport implements ModelDriven<User> { /** * 方式三 使用模型驱动 */ //这里需要注意,方法2中的user对象不需要自己创建,而这里必须手动初始化 private User user = new User(); public User getModel() { return user; } @Override public String execute() throws Exception { System.out.println( "user:" +user); return NONE; } } /* * 如果jsp界面输入:用户名:aa 兴趣爱好:体育读书 * 后台输出:user:User [username=aa, hobby=[sport, music]] */ |
最后我们来思考两个问题,也是常见的笔面试题:
问题一:Action封装数据会不会有线程问题?
问题二:在使用第一种方式进行封装的时候数据封装到Action 属性中不能把Action传递给业务层数据如何传递?
谢谢大家浏览,欢迎大家指点!
Struts2系列笔记(7)---Struts2类型转换
Struts2类型转换
struts2中内置了大量的类型转换器用来完成数据类型转换的问题,这篇随笔主要通过两个方面来写Struts类型转换
1:Struts2内置的类型转换器
2:如何自定义类型转换器
那么首先我们来学习有关Struts2内置的类型
1:Struts2内置的类型转换器
Struts2的内置类型转换器,可以为你处理大多数的类型转换,这包括了以下类型和String类型之间的转换!
1.String
将int,double,boolean,String类型的数组或java.util.Date类型转换成字符串。
2:boolean和Boolean
在字符串与boolean之间转换
3:char/Character
在字符串和字符之间转换
4:int/Integer,float/Float,long/Long,double/Double
在字符串与数值类型之间进行转换
5:date
在字符串和日期类型之间进行转换,默认格式是:YYYY-MM-DD
6:数组
由于数组本身就有类型,可以将多个同名参数,转换到数组中(在之前总结的兴趣爱好多选择,如果你选择多个,同时他们name属性相同就自动变为数组)
7:集合
支持将数据保存到 List 或者 Map 集合
关于内置类型转换器举例:
Action类
1 import java.util.Date; 2 import com.opensymphony.xwork2.ActionSupport; 3 4 public class CustomerAction extends ActionSupport { 5 6 private String username; 7 8 private int age; 9 10 private Date birthday; 11 12 @Override 13 public String execute() throws Exception { 14 System.out.println("客户姓名是:" + username + ",年龄是:" + age + ",生日:" + birthday); 15 16 return NONE; 17 } 18 public void setUsername(String username) { 19 this.username = username; 20 } 21 public void setAge(int age) { 22 this.age = age; 23 } 24 public void setBirthday(Date birthday) { 25 this.birthday = birthday; 26 } 27 } 28 /*控制台输出结果:客户姓名是:zhangsan,年龄是:12,生日:Tue Jul 09 00:00:00 CST 1996 29 */
jsp界面
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <html> 3 <head> 4 </head> 5 <body> 6 <form action="${pageContext.request.contextPath }/customer.action"> 7 客户姓名:<input type="text" name="username"><br/> 8 年龄:<input type="text" name="age"><br/> 9 生日:<input type="text" name="birthday"><br/> 10 <input type="submit" value="提交"> 11 </form> 12 </body> 13 </html>
界面输入:这里年龄只能输入合法年龄,日期的默认格式:yyyy-MM-dd,如果你输入不合规则网页会报错,比如你输入1996/7/9页面就会报错
2:如何自定义类型转换器
为什么需要自定义类型转换器,这个问题相信大家都知道,就像我上面所说的,日期的默认格式是yyyy-MM-dd,那如果你想输入yyyy/mm/dd或者其它的
这个时候就需要你修改你自己的类型转换器,否则会报错。下面我写一个有关自定义类型转换器的方法: 继承StrutsTypeConverter
DateConverter
1 import java.text.DateFormat; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.Map; 6 7 import javax.xml.bind.TypeConstraintException; 8 import org.apache.struts2.util.StrutsTypeConverter; 9 10 public class DateConverter extends StrutsTypeConverter { 11 //为方便支持多种日期格式的转换,可增加时间格式 12 private final DateFormat [] dateformats={ 13 new SimpleDateFormat("yyyy-MM-dd"), 14 new SimpleDateFormat("yyyy年MM月dd日"), 15 new SimpleDateFormat("yyyy.MM.dd"), 16 new SimpleDateFormat("yyyy/MM/dd") 17 }; 18 /* 将一个或多个字符串值转换为指定的类型 19 * 20 */ 21 @Override 22 public Object convertFromString(Map arg0, String[] values, Class toType) { 23 //从表单获取的日期字符串 24 String dateStr = values[0];//思考:这里为什么是数组而不是字符串?我自己也没有搞明白,希望大神看到后宰评论区给予解答,谢谢 25 for(int i = 0;i<dateformats.length;i++){//遍历日期类型进行转换 26 27 try { //SimpleDateFormat类中parse()方法用于将输入的特定字符串转换成Date类的对象 28 return dateformats[i].parse(dateStr); 29 } catch (Exception e) { 30 continue; //很关键 31 } 32 } 33 throw new TypeConstraintException("遍历结束仍没有指定的类型转换"); 34 } 35 36 /* 将指定对象转化为字符串 37 * method:这个方法是用来回显用的,就是你需要回显成什么样的格式就可以设置什么样的格式 38 */ 39 @Override 40 public String convertToString(Map context, Object object) { 41 Date date = (Date) object; 42 //指定输出的格式 43 return new SimpleDateFormat("yyyy年MM月dd日").format(date); 44 } 45 } 46 /*主要讲这里的continue,就是如果你是输入的是1992-2-2,那么dateformats[0]和你直接匹配 47 * 那么直接返回,当如果你开始输入的是1992/2/2那么就和dateformats[0]不匹配,那么出现异常执行 48 * catch中的内容,而catch中是continue代表终止本次循环进入下一次循环,那么有和dateformats[1] 49 * 进行匹配,如果都不匹配才会异常,所以这里用的太关键了 50 *
Aation(类)
1 import java.util.Date; 2 import com.opensymphony.xwork2.ActionSupport; 3 4 public class RegisterAction1 extends ActionSupport { 5 private Date brithday1; 6 private Date brithday2; 7 private Date brithday3; 8 private Date brithday4; 9 /* 10 * 为上面四个提供set和get方法 11 */ 12 13 @Override 14 public String execute() throws Exception { 15 //获取表单的数据 16 System.out.println("生日1"+brithday1); 17 System.out.println("生日2"+brithday2); 18 System.out.println("生日3"+brithday3); 19 System.out.println("生日4"+brithday4); 20 return SUCCESS; 21 } 22 } 23 /*后台输出结果: 24 * 生日1Sun Feb 02 00:00:00 CST 1992 25 * 生日2Sun Feb 02 00:00:00 CST 1992 26 * 生日3Sun Feb 02 00:00:00 CST 1992 27 * 生日4Sun Feb 02 00:00:00 CST 1992 28 */
register.jsp(登录界面)
1 <html> 2 <head> 3 <title>注册</title> 4 </head> 5 <body> 6 <!-- 这里有四个生日 --> 7 <form action="${pageContext.request.contextPath }/register1.action" method="post"> 8 生日1:<input type="text" name="brithday1"><br/><br/> 9 生日2:<input type="text" name="brithday2"><br/><br/> 10 生日3:<input type="text" name="brithday3"><br/><br/> 11 生日4:<input type="text" name="brithday4"><br/><br/> 12 <input type="submit" value="注册"> 13 </form> 14 </body> 15 </html>
struts.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <!-- 开发者模式 --> 7 <constant name="struts.devMode" value="true"></constant> 8 9 <package name="default" extends="struts-default"> 10 <action name="register1" class="com.guigu.struts2.action.RegisterAction1"> 11 <result>/result.jsp</result> 12 </action> 13 </package> 14 </struts>
result.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri="/struts-tags" prefix="s"%> 3 <html> 4 <head> 5 </head> 6 <body> 7 <!-- 回显的时候发现尽管前面输入格式不一样,但输出格式是一样的 --> 8 生日1:<s:property value="brithday1"/><br/> 9 生日2:<s:property value="brithday2"/><br/> 10 生日3:<s:property value="brithday3"/><br/> 11 生日4:<s:property value="brithday4"/><br/> 12 </body> 13 </html>
界面:
最终返回界面:
注意:这中间还有很重要的东西需要配置:配置转换器
这篇文字就讲到这里,如果哪里有不足,欢迎大家指点,谢谢
Struts2框架(8)---Struts2的输入校验
Struts2的输入校验
在我们项目实际开发中在数据校验时,分为两种,一种是前端校验,一种是服务器校验:
客户端校验:主要是通过jsp写js脚本,它的优点很明显,就是输入错误的话提醒比较及时,能够减轻服务器的负担,但是客户端校验并不是安全的,简单来讲就是防君子防不了小人。
服务器端校验:最大特点就是数据安全,但是如果只有服务器端校验,会大大增加服务器端的负担。
所以一般在我们开发中,是客户端和服务器端校验相结合作用的。
那这篇文章,我只讲服务器端校验,在Struts2支持两种校验方式:
代码校验 :在服务器通过编辑java代码完成数据校验
配置校验: xml配置校验 通过xml配置文件完成数据的校验
(1)代码校验:
代码校验分为三个步骤:
步骤一、封装数据
步骤二、实现要校验的Action 必须继承ActionSupport
步骤三、覆盖Validate方法 然后完成业务逻辑数据的校验
用户界面 register.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 <%@ taglib uri="/struts-tags" prefix="s" %> 4 <html> 5 <head> 6 <title>用户注册</title> 7 </head> 8 <body style="text-align: center;"> 9 <table align="center" width="50%"> 10 <tr> 11 <td style="color: red"> 12 <!-- <s:fielderror></s:fielderror> --> <!-- 这里是显示错误的地方 --> 13 </td> 14 </tr> 15 </table> 16 17 <form action="${pageContext.request.contextPath }/login" method="post" > 18 19 用户名:<input type="text" name="username"><br><br> 20 密 码:<input type="text" name="password"><br><br> 21 确认密码:<input type="text" name="password2"><br><br> 22 <input type="reset" value="清空"> 23 <input type="submit" value="注册"> 24 25 </form> 26 </body> 27 </html>
struts.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <!-- 配置常量信息 --> 7 <constant name="struts.devMode" value="true"></constant> 8 9 <package name="struts2" extends="struts-default" > 10 <action name="login" class="com.study.Login.RegisterAction"> 11 <result name="success">/success.jsp</result> 12 <!-- 在input视图中可以通过<s:fielderror/>显示失败信息 --> 13 <result name="input">/register.jsp</result> 14 </action> 15 </package> 16 </struts>
RegisterAction.java
1 import com.opensymphony.xwork2.ActionSupport; 2 public class RegisterAction extends ActionSupport{ 3 4 private String username; 5 private String password; 6 private String password2; 7 //这里我通过set方法封装数据 8 public void setUsername(String username) { 9 this.username = username; 10 } 11 public void setPassword(String password) { 12 this.password = password; 13 } 14 public void setPassword2(String password2) { 15 this.password2 = password2; 16 } 17 18 @Override 19 public String execute() throws Exception { 20 return NONE; 21 } 22 23 //在服务器端需要完成对数据的校验 24 @Override 25 public void validate() { 26 //测试是否得到属性值,证实已经得到 27 System.out.println(username+"---"+password+"---"+password2); 28 if(username==null || username.length()<6 || username.length()>20){ 29 //把错误信息保存到字段中 30 this.addFieldError("username", "有户名输入不合法"); 31 } 32 33 if(password==null || password.length()<6 || password.length()>20){ 34 //把错误信息保存到字段中 35 this.addFieldError("password", "密码输入不合法"); 36 }else if( password2==null || password2.length()<6 || password2.length()>20){ 37 this.addFieldError("password2", "密码输入不合法"); 38 }else if(!password.equals(password2)){ 39 this.addFieldError("password2", " 两次密码不一致"); 40 } 41 42 super.validate(); 43 } 44 }
运行结果:
(2)框架校验
框架校验也就是通过XML配置方式进行数据校验 ,这也是我们在企业开发的主流校验。
XML校验原理: 将很多规则代码已经写好只需要在xml文件中定义需要使用的校验规则即可。,所以大大减少了我们的开发时间。
我先把步骤写一下:
步骤一:编写JSP
步骤二:编写Action 继承ActionSupport或者Validateable接口
步骤三:封装请求参数
步骤四:编写xml校验规则文件
Xml校验文件的命名规则: Action类名-validation.xml 对Action中所有的方法都执行校验
举例命名规则RegisterAction-validation.xml
同时要满足:Xml校验文件和Action类要在同一包下
步骤一: register.jsp
步骤二:RegisterAction.java
import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class RegisterAction extends ActionSupport implements ModelDriven<User>{ //手动创建一个对象 private User user =new User(); @Override public String execute() throws Exception { return NONE; } public User getModel() { return user; } }
步骤三:封装请求参数
上面手动校验的案例我是用set方法封装数据,那这里我采用的是使用ModelDriven接口,对请求数据进行封装,
在之前我讲过封装数据的三种方法不清楚的可以看下这篇文章:Struts框架(6)---action接收请求参数
User.java
1 import java.util.Date; 2 public class User { 3 4 private String username; 5 private String password; 6 private String password2; 7 private Integer age; 8 private String email; 9 private Date birthday; 10 private Date graduation; 11 12 /* 13 * 给属性提供get和set方法 14 */ 15 }
步骤四:RegisterAction-validation.xml
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators> <!--dtd约束在xwork-core-**.jar包中 --> <field name="username"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>用户民不能为空</message> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">15</param> <message>有户名长度必须在 ${minLength} 和 ${maxLength}之间 </message> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>密码不能为空</message> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">15</param> <message>密码必须在 ${minLength}和${maxLength}之间 </message> </field-validator> </field> <field name="password2"> <field-validator type="fieldexpression"> <param name="expression"><![CDATA[password==password2]]></param> <message>两次密码不一致</message> </field-validator> </field> <field name="age"> <field-validator type="required"> <param name="trim">true</param> <message>年龄不能为空</message> </field-validator> <field-validator type="int"> <param name="min">1</param> <param name="max">150</param> <message>年龄必须在 ${min} 和 ${max}之间</message> </field-validator> </field> <field name="email"> <field-validator type="email"> <message>不是一个合法的邮箱地址</message> </field-validator> </field> <field name="birthday"> <field-validator type="date"> <param name="min">2001-01-01</param> <param name="max">2003-12-31</param> <message>生日必须在 ${min} 和${max}之间</message> </field-validator> </field> </validators>
struts.xml不需要任何改变,和之前一样就可以了
运行结果:
如果你觉得提示错误的位置有点丑,那你可以运用Struts2的<s:form>标签,效果会更好
现在两种方式都讲了,现在对xml配置的要点一些知识要点进行归纳。
xml校验文件详解:
<validators>: 根元素
<field>:指定action中要校验的属性,name属性指定将被验证的表单字段的名字
<field-validator>:指定校验器, type 指定验证规则
上面指定的校验器requiredstring是由系统提供的,系统提供了能满足大部分验证需求
的校验器,这些校验器的定义可以在xwork-2.x.jar中的
com.opensymphony.xwork2.validator.validators下的default.xml中找到。
<param>:子元素可以向验证程序传递参数
<message>:子元素为校验失败后的提示信息,如果需要国际化,可以为message
指定key属性,key的值为属性文件中的key。
struts2校验规则:
系统提供的校验器如下:
required (必填校验器,要求被校验的属性值不能为null)
requiredstring (必填字符串校验器,要求被校验的属性值不能为null,并且长度大于0,默认情况下会对字符串去前后空格)
stringlength(字符串长度校验器,要求被校验的属性值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格)
regex(正则表达式校验器,检查被校验的属性值是否匹配一个正则表达式,expression参数指定正则表达式,caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)
int(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)
double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)
fieldexpression(字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过)
email(邮件地址校验器,要求如果被校验的属性值非空,则必须是合法的邮件地址)
url(网址校验器,要求如果被校验的属性值非空,则必须是合法的url地址)
date(日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)
conversion(转换校验器,指定在类型转换失败时,提示的错误信息)
visitor(用于校验action中复合类型的属性,它指定一个校验文件用于校验复合类型属性中的属性)
expression(OGNL表达式校验器,它是一个非字段校验器, expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中)
最后讲一个细节:
编写校验文件时,不能出现帮助信息
在编写ActionClassName-validation.xml校验文件时,如果出现不了帮助信息,可以按下面方式解决:
windwos->preferences->myeclipse->files and editors->xml->xmlcatalog
点“add”,在出现的窗口中的location中选“File system”,然后在xwork-2.1.2解压目录的src\java目录中选择xwork-validator-1.0.3.dtd,
回到设置窗口的时候不要急着关闭窗口,应把窗口中的Key Type改为URI 。Key改为http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd