第一天:
struts2是在WebWork基础上发展而来的,也属于MVC框架。
struts2和struts1名字上很像,但是他们是完全不同的。
struts具有以下的优点:
struts2的优点:
1、struts2不依赖与ServletAPI和strutsAPI
2、struts2提供了拦截器
3、struts2提供了类型转换器,我们可以把特殊的请求参数转换为需要的类型
4、struts2提供支持多种表现层的技术如 JSP、freeMarker、Velocity等
5、struts2输入校验可以对指定方法进行校验
6、struts2提供全局范围、包范围、和Action范围的国际化资源文件管理实现
struts2开发步骤:
1、struts2 开发所需要的架包。
2、编写struts2的配置文件
struts2的默认配置文件是struts.xml文件,在WEB-INF/classes下。该文件的模板文件如下:
<?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> </struts>
注意:此文件在开发的时候是放到src目录下,程序编译后会自动拷贝到WEB-INF/classes目录下。
3、在web.xml中加入struts2 MVC框架的初始配置。
struts2框架是通过Filter启动的,他在xml的配置如下:
<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>
在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。
注意:struts2读取到struts.xml的内容后,以javabean形式存放在内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件
struts.xml 文件的说明:
<package name="itcast" namespace="/test" extends="struts-default"> <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute" > <result name="success">/WEB-INF/page/hello.jsp</result> </action> </package>
在struts2文件中通过package来管理action
name属性可以任意取,但是要保证其唯一性,主要是被其他包使用。
namespace主要作为访问action路径的一部分
extends 继承于哪个包
action name可以作为访问该action路径的一部分。
每个包都继承于struts-defult
class 访问该类需要处理的类。
第二天:
转发和重定向。
action中result默认的就是服务器内部请求转发(dispatcher)
redirect:浏览器重定向,引导用户浏览器访问某个路径,不能访问WEB-INF下边的JSP,只有服务器内部可以访问。
dispatcher 和redirect区别:内部定向不会显示到浏览器地址栏中,也就是jsp里面的转发器,用户看不到地址栏的变化。
redirectAction:重定向到一个Action。
如果不在一个里边的Action,重定向请求时候,需要:
redirectAction对应一个Java类,该类里边有两个setActionName()和setNamespace()
<param name="actionName">xxx</param> <param name="namespace">/</param>
在package配置中:
extends="struts-default"
这一项不是默认配置的,必须要配置。
还可以进行配置全视图:
<global-results> <result name="message">/WEB-INF/message/message.jsp</result>
</global-results>
跨包使用全局视图,可以通过继承包就可以实现。
第三天:为Action属性注入值
通过<param>标签,name为变量的名字,标签体为值。
<action name="hello" class="cn.lyjs.web.action.Hello" > <param name="path">/WEB-INF/jsp/hello.jsp</param> <result name="success">/WEB-INF/jsp/hello.jsp</result> </action>
2、指定struts2处理的请求后缀
<constant name="struts.action.extension" value="do"></constant>
3、常量的配置
最好在struts.xml 文件中定义常量。
4、struts2的处理过程
用户请求到达---StrutsPrepareAndExecuteFilter过滤------》进入Struts2框架-------》经过一系列Interceptor----》action---->Resutlt--->Jsp/html
struts2对于用户的每一次请求都会创建一个Action,所以Struts2中的Action是线程安全的。
5、为应用指定多个配置文件
把一个stuts.xml配置文件拆分成多个配置文件,然后再struts.xml文件中包含其他配置文件
<include file="文件的地址"/>
第四天:
1、动态方法调用
直接在请求地址后边:!方法名(很少使用)
禁止方法如下:
<constant name="struts.enable.DynamicMethodInvocation" value="false"></constant>
2、使用通配符
<action name="hello_*" class="cn.lyjs.web.action.Hello" method="{1}" > <result name="success">/WEB-INF/jsp/hello.jsp</result>
</action>
获取*时候,用{1},1代表第几个*号。
3、接受请求参数:
在Action中定义与请求参数同名的属性
使用JavaBean来接收参数,person.id,person.name 来获得参数的值
4、struts2类型转换器:
局部:
1、首先要写一个类来继承DefaultTypeConverter
2、然后覆盖convertValue这个方法,在里面进行数据转型
3、在action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是类名,后面的-conversion.properties是固定的写法,
4、d.Properties文件里面的内容为:属性名称=类型转换器的全类名(既包名.类名)
如:birthday=com.ljq.type.converter.DateTypeConverter
package cn.lyjs.type.conserver; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter; public class HelloDate extends DefaultTypeConverter { @Override public Object convertValue(Map<String, Object> context, Object value, Class toType) { //必须以这个格式严格输入 SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd"); try{ if(toType==Date.class){ //转化为Date类型 String[] params=(String[]) value; return sdf.parseObject(params[0]); }else if(toType==String.class){ //转化为字符类型 Date date=(Date) value; return sdf.format(date); } } catch (ParseException e) { } return null; } }
访问或添加几个属性
通过ActionContext来访问
ServletContext、session、request
1、通过ActionContext进行获取(仅仅需要添加属性)
ActionContext ac=ActionContext.getContext();
ac.getApplication().put("app", "应用范围");
ac.getSession().put("ses","session范围");
ac.put("req", "request范围");
2、通过ServletActionContext类直接获取(获取绝对路径的)
HttpServletRequest request=ServletActionContext.getRequest();
ServletContext servletContext=ServletActionContext.getServletContext();
servletContext.setAttribute("app", "应用属性范围");
request.setAttribute("req", "请求属性范围");
request.getSession().setAttribute("ses","绘话属性范围");
<c:forEach items="${names } var="name"> ${name }<br/> </c:forEach>
public class HelloWorldAction { public String execute(){ ActionContext ac=ActionContext.getContext(); ac.getApplication().put("app", "应用范围"); ac.getSession().put("ses","session范围"); ac.put("req", "request范围"); ac.put("names", Arrays.asList("价格","答案","发个")); return "success"; } public String rsa() throws Exception{ HttpServletRequest request=ServletActionContext.getRequest(); ServletContext servletContext=ServletActionContext.getServletContext(); servletContext.setAttribute("app", "应用属性范围"); request.setAttribute("req", "请求属性范围"); request.getSession().setAttribute("ses","绘话属性范围"); return "success"; } }
第四天:
文件上传
1、把form的enctype设置为multipart-data
2、private File uploadImage;
private String uploadImageFileName ; 得到文件的名称
3、
public String execute() throws IOException{ //在 WEB-INF下边创建 images 文件 String realpath=ServletActionContext.getServletContext().getRealPath("/WEB-INF/images"); if(image!=null){ File savefile=new File(new File(realpath),imageFileName); //创建一个实例而已,而不是创建一个文件 if(!savefile.getParentFile().exists()) savefile.getParentFile().mkdirs();//创建多级目录 FileUtils.copyFile(image, savefile);//savefile只是一个实例,现在根据这个实例,把image内容,写入到这个实例的文件中 ActionContext.getContext().put("message", "上传成功"); } return "success"; }
多文件上传:
public class Hello { private File[] image; private String[] imageFileName; public File[] getImage() { return image; } public void setImage(File[] image) { this.image = image; } public String[] getImageFileName() { return imageFileName; } public void setImageFileName(String[] imageFileName) { this.imageFileName = imageFileName; } public String execute() throws IOException{ //在 WEB-INF下边创建 images 文件 String realpath=ServletActionContext.getServletContext().getRealPath("/WEB-INF/images"); System.out.println(realpath); if(image!=null){ File file=new File(realpath); if(!file.exists()) file.mkdirs(); for(int i=0;i<image.length;i++){ File savefile=new File(file,imageFileName[i]); FileUtils.copyFile(image[i], savefile); } ActionContext.getContext().put("message", "上传成功"); } return "success"; }
第五天:
自定义拦截器
1、拦截器类必须继承于Interceptor
package cn.lyjs.interceptors; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class PermissionInterceptor implements Interceptor{ public void destroy() { } public void init() { } public String intercept(ActionInvocation invocation) throws Exception { Object session=ActionContext.getContext().getSession().get("user"); if(session!=null) return invocation.invoke();//执行该action ActionContext.getContext().put("message", "你没有权限查看,请你先登录"); return "success"; } }
2、配置
配置拦截器栈,默认的栈排在第一个。
<package name="test" namespace="/" extends="struts-default"> <interceptors> <interceptor name="permission" class="cn.lyjs.interceptors.PermissionInterceptor"/> <interceptor-stack name="permissionStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="permission"/> </interceptor-stack> </interceptors> <global-results > <result name="success">/WEB-INF/jsp/hello.jsp</result> </global-results> <action name="hello" class="cn.lyjs.web.action.Hello" method="execute"> <interceptor-ref name="permissionStack"/> </action> </package>