title: Struts2
Struts2
简介:控制器框架
控制器框架:简化servlet原本收参,传参,跳转的过程
Struts2使用
在web.xml文件中配置
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置action的访问路径(struts.xml)
struts.xml在src下
<!-- package:给请求分类,在正常的项目开发中,将项目分成多个模块,例:用户管理模块,商品管理模块。。。。
用户管理模块:登陆,注册,注销。。。。
一般情况下,会将同一个模块的功能写在同一个package中
属性: name:给当前包起名字,名字随便起,同一个struts.xml中不能重复
-->
<package name="p1" extends="struts-default" >
<!-- action : 一个action配置一个请求路径,在一个package中可以写多个action
属性: name:配置请求路径,注意,不要加“/”
class:当该action被请求时,执行哪个类 默认执行类中的execute方法
-->
<action name="first" class="com.baizhi.action.FirstAction">
<!-- result: action执行完之后的跳转配置
属性 name:execute方法的返回值
-->
<result name="ok">/index.jsp</result>
</action>
</package>
struts.xml详解
package标签中的namespace属性
<package name="p1" extends="struts-default" namespace="/hero" >
<!-- action : 一个action配置一个请求路径,在一个package中可以写多个action
属性: name:配置请求路径,注意,不要加“/”
class:当该action被请求时,执行哪个类 默认执行类中的execute方法
-->
<action name="first" class="com.baizhi.action.FirstAction">
<!-- result: action执行完之后的跳转配置
属性 name:execute方法的返回值
-->
<result name="ok">/index.jsp</result>
</action>
</package>
作用:在p1包下的所有action请求,请求路径要加上namespace的值
例:要请求上述的first -》Action
lcoalhost:8989/webappName/hero/first
action中的method属性
<!--action中没有method属性,默认为execute方法,写了method属性,执行的是method中的方法-->
<action name="first" class="com.baizhi.action.FirstAction" method="a">
<!-- result: action执行完之后的跳转配置
属性 name:execute方法的返回值
-->
<result name="ok">/index.jsp</result>
</action>
public class FirstAction extends ActionSupport {
@Override
public String execute() throws Exception {
//请求的具体内容
System.out.println("-------sturts do-------");
//返回字符串
//内容随便写,作用一会儿在配置struts.xml的时候有用
return "ok";
}
public String a() {
System.out.println("我是a,我被执行了,哈哈哈啊哈。。。。。。");
return "ok";
}
}
<!--如果添加了method属性,那么在action中自定义的方法,必须为公开无参的,返回值为String的方法,方法名要和method中的一致-->
result标签中的type属性
-
作用:确定跳转方式(转发,重定向)
-
action转发到jsp
<result name="ok" type="dispatcher" ></result>
-
action重定向导jsp
<result name="ok" type="redirect">/XXX.jsp</result>
-
action转发到action(不常用)
<result name="ok" type="chain">action的name属性值</result> 注意:不能加“/“
-
action重定向导action
同包重定向 <result name="ok" type="redirectAction">action的name属性值</result> 注意:不能加“/“ 特例:跨包重定向 <action name="login" class="com.baizhi.action.UserAction" method="login"> <!-- 登陆成功 跨包重定向查询所有的action --> <result name="loginOk" type="redirectAction" > <param name="namespace">/pro</param> <param name="actionName">selectAll</param> </result> </action>
-
Struts接收请求参数
-
使用servlet接收请求参数
String value = request.getParameter("key");
-
在struts中获取request对象
public String a() { HttpServletRequest request = ServletActionContext.getRequest(); String name = request.getParameter("name"); System.out.println(name); System.out.println("我是a,我被执行了,哈哈哈啊哈。。。。。。"); return "ok"; }
-
用struts方式接收
接收简单类型
步骤:
在action中定义一个属性,属性名与参数的key相同
给此属性生成标准的get和set方法
- 标准get/set的生成过程:属性首字母大写,其他字母不变,然后最前面添加get/set
private Stirng userName; public String getUserName(){} public void setUserName(String userName){} private String eName; public String getEName(){} public void setENname(){}
public class FirstAction { private String name; private int age; public String a() { System.out.println("我是a,我被执行了,哈哈哈啊哈。。。。。。"); System.out.println("这是前端传来的值:"+name); System.out.println("这是前端传来的age+1的值:"+(age+1)); return "ok"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
接收对象类型
接收对象
- 创建标准实体类
- 标准实体类:无参构造方法噶,所有属性的标准get和set方法
- 只能多不能少
- 在action中创建对象属性,提供get和set
- 在前端要给对象赋值,前端的key的写法为对象名.属性名
接收集合数组
定义标准实体类
在action中创建一个集合属性(数组属性,提供get/set)
public class FirstAction { private List<Integer> ids; public String a() { System.out.println("我是a,我被执行了,哈哈哈啊哈。。。。。。"); System.out.println(ids); return "ok"; } public List<Integer> getIds() { return ids; } public void setIds(List<Integer> ids) { this.ids = ids; } }
<form action="${pageContext.request.contextPath }/hero/first"> <input type="checkbox" name="ids" value="1" /><br/> <input type="checkbox" name="ids" value="2" /><br/> <input type="checkbox" name="ids" value="3" /><br/> <input type="checkbox" name="ids" value="4" /><br/> <input type="checkbox" name="ids" value="5" /><br/> <input type="checkbox" name="ids" value="6" /><br/> <input type="checkbox" name="ids" value="7" /><br/> <input type="checkbox" name="ids" value="8" /><br/> <input type="submit" /> </form>
Struts操纵作用域保存内容
request
在action中定义属性,提供get/set方法
在重写的action方法中给此属性赋值,就相当于,把内容存入了request中,key为属性名,值为你存入的值
public class ProductAction { private User user; public String selectAll() { //创建user对象 User u = new User(1, "贾莎莎", "666666"); //将对象赋值给属性 //相当于往req中保存一个键值对 键为user 值为u对象 “user”=user[id=1,name="asa",pwd="66666"] user = u; System.out.println("----------查询所有---------"); return "selectAllOk"; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
<body> <h1>我是展示商品页面</h1> ${requestScope.user } </body>
session
//获取session HttpServletRequest request = SerlvetActionContext.getRequest(); HttpSession session = request.getSession(); //存 session.setAttribute("key",value); //取 session.getAttribute("key");
Struts运行流程
如果想要强制登陆过滤器起效果,就必须保证强制登陆过滤器要先于核心过滤器被执行,
过滤器执行顺序与其在web.xml中的配置顺序有关,谁先被配置谁想被执行
结论:强制登陆的filter必须要放在struts核心过滤器之前
通配符
目前在struts.xml中的action配置过于繁琐,通常一个package中会有很多action标签
<package name="product" extends="struts-default" namespace="/pro"> <!-- 查询所有的action --> <action name="selectAll" class="com.baizhi.action.ProductAction" method="selectAll"> <!-- 转发到查询所有的页面 show.jsp --> <result name="selectAllOk" type="dispatcher">/show.jsp</result> </action> <!-- 添加的action --> <action name="insert" class="com.baizhi.action.ProductAction" method="insert"> <!-- 重定向到查询所有的action --> <result name="insertOk" type="redirectAction">selectAll</result> </action> <!-- 删除的action --> <action name="delete" class="com.baizhi.action.ProductAction" method="delete"> <!-- 重定向到查询所有的action --> <result name="deleteOk" type="redirectAction">selectAll</result> </action> <!-- 修改的action --> <action name="update" class="com.baizhi.action.ProductAction" method="update"> <!-- 重定向到查询所有的action --> <result name="updateOk" type="redirectAction">selectAll</result> </action> </package>
<package name="product" extends="struts-default" namespace="/pro"> <!-- 查询所有的action --> <action name="pro_*" class="com.baizhi.action.ProductAction" method="{1}"> <!-- 转发到查询所有的页面 show.jsp --> <result name="selectAllOk" type="dispatcher">/show.jsp</result> <result name="Ok" type="redirectAction">pro_selectAll</result> </action> </package>
验证码
导入糊涂工具包,要求JDK1.8以上
代码实现:
public class CodeAction { private ByteArrayInputStream stream; public String code() { //画验证码 CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 50, 4, 4); //返回给img标签 //需要用到流 stream = new ByteArrayInputStream(captcha.getImageBytes()); //将验证码对象放入session中 HttpSession session = ServletActionContext.getRequest().getSession(); session.setAttribute("realCode", captcha); return "codeOk"; } public ByteArrayInputStream getStream() { return stream; } public void setStream(ByteArrayInputStream stream) { this.stream = stream; } }
<package name="code" extends="struts-default"> <action name="code" class="com.baizhi.action.CodeAction" method="code"> <result name="codeOk" type="stream"> <!-- 指明传送内容的格式 --> <param name="contentType">image/jpeg</param> <!-- 指明流的名字,在action中流属性的名字 --> <param name="inputName">stream</param> <!-- 流缓存大小 --> <param name="bufferSize">2048</param> </result> </action> </package>
//登陆的action public class UserAction { private String userCode; public String login() { //判断用户输入的验证码是否正确 // 1.从session中取验证码 HttpSession session = ServletActionContext.getRequest().getSession(); CircleCaptcha captcha = (CircleCaptcha)session.getAttribute("realCode"); if(captcha.verify(userCode)) { //验证码正确 return "loginOk"; }else { //验证码错误 return "loginBuOk"; } //判断用户密码 } public String Regist() { System.out.println("-------注册成功-------"); return "registOk"; } public String getUserCode() { return userCode; } public void setUserCode(String userCode) { this.userCode = userCode; } }
action的生命周期
- 问题:之前我们说过不能在serlvet中定义属性,原因是多个用户使用同一个servlet对象,定义属性会出现临界资源,导致线程不安全,但现在我们在action却可以定义属性,这是为什么
- 创建:每一个action请求过来时都会创建一个新的action对象
销毁:当本次请求结束时,action对象立即被销毁
在一个请求发送过来时,会创建一个action对象,并且执行请求对应的方法,当方法执行完时,对象会马上被销毁
不同用户发送的请求,action对象不一样
相同用户发送的两次请求,action对象不一样
结论:由于每次请求使用的action对象不同,所以在action中定义属性,不会产生临界资源,不会发生线程不安全的问题
Struts拦截器
拦截器:当一个请求请求某个action时,拦截器会拦截此请求,先执行拦截器中的内容,并且决定是否让该请求放行,去执行原本要请求的action
步骤
1.自定义类,实现interceptor接口
public class MyInterceptor implements Interceptor { @Override public void destroy() { // TODO Auto-generated method stub //拦截器被销毁时调用 } @Override public void init() { // TODO Auto-generated method stub //拦截器被创建时调用 } @Override public String intercept(ActionInvocation ai) throws Exception { // TODO Auto-generated method stub //拦截器的具体实现 System.out.println("我是拦截器,我被调用了,哈哈哈啊哈哈。。。。。"); //放行 //invoke方法有返回值,返回值的内容为action方法的返回值内容 String invoke = ai.invoke(); return invoke; } }
2.struts.xml中注册拦截器
<package name="p1" extends="struts-default"> <!-- 注册拦截器 --> <interceptors> <interceptor name="myInt" class="com.baizhi.interceptor.MyInterceptor"></interceptor> </interceptors> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <result name="ok">/index.jsp</result> </action> </package>
3.使用拦截器
<action name="a" class="com.baizhi.action.TestAction" method="ma"> <!-- 使用拦截器 --> <interceptor-ref name="myInt"></interceptor-ref> <result name="ok">/index.jsp</result> </action>
拦截器详解
当有多个拦截器时执行先后
在action中,谁先被使用,谁先运行,跟注册顺序无关
<package name="p1" extends="struts-default"> <!-- 注册拦截器 --> <interceptors> <interceptor name="myInt" class="com.baizhi.interceptor.MyInterceptor"></interceptor> <interceptor name="bInt" class="com.baizhi.interceptor.BInterceptor"></interceptor> </interceptors> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <!-- 使用拦截器 --> <interceptor-ref name="bInt"></interceptor-ref> <interceptor-ref name="myInt"></interceptor-ref> <result name="ok">/index.jsp</result> </action> </package> 结果:bInt先执行,myInt后执行
拦截器栈
当有多个action同时需要相同的多个拦截器时,可以使用拦截器栈
<package name="p1" extends="struts-default"> <!-- 注册拦截器 --> <interceptors> <interceptor name="myInt" class="com.baizhi.interceptor.MyInterceptor"></interceptor> <interceptor name="bInt" class="com.baizhi.interceptor.BInterceptor"></interceptor> <!-- 拦截器栈 --> <interceptor-stack name="myStack"> <interceptor-ref name="myInt"></interceptor-ref> <interceptor-ref name="bInt"></interceptor-ref> </interceptor-stack> </interceptors> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <!-- 使用拦截器栈 --> <interceptor-ref name="myStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> <action name="b" class="com.baizhi.action.TestAction" method="mb"> <interceptor-ref name="myStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> </package>
父包
在不同的包中需要使用到相同拦截器
<package name="father" extends="struts-default"> <!-- 注册拦截器 --> <interceptors> <interceptor name="myInt" class="com.baizhi.interceptor.MyInterceptor"></interceptor> <interceptor name="bInt" class="com.baizhi.interceptor.BInterceptor"></interceptor> <!-- 拦截器栈 --> <interceptor-stack name="myStack"> <interceptor-ref name="myInt"></interceptor-ref> <interceptor-ref name="bInt"></interceptor-ref> </interceptor-stack> </interceptors> </package> <package name="p1" extends="father"> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <!-- 使用拦截器 --> <interceptor-ref name="myStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> <action name="b" class="com.baizhi.action.TestAction" method="mb"> <interceptor-ref name="myStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> </package> <package name="p2" extends="father"> <action name="testB" class="com.baizhi.action.TestBAction" method="testB"> <interceptor-ref name="myStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> </package> p1,p2包都继承了father包,那么在father包中所定义的所有内容,p1和p2包都能使用
设置默认使用拦截器
<struts> <package name="father" extends="struts-default"> <!-- 注册拦截器 --> <interceptors> <interceptor name="myInt" class="com.baizhi.interceptor.MyInterceptor"></interceptor> <interceptor name="bInt" class="com.baizhi.interceptor.BInterceptor"></interceptor> <!-- 拦截器栈 --> <interceptor-stack name="myStack"> <interceptor-ref name="myInt"></interceptor-ref> <interceptor-ref name="bInt"></interceptor-ref> </interceptor-stack> </interceptors> 设置默认使用拦截器 <default-interceptor-ref name="myStack"></default-interceptor-ref> </package> <package name="p1" extends="father"> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <result name="ok">/index.jsp</result> </action> <action name="b" class="com.baizhi.action.TestAction" method="mb"> <result name="ok">/index.jsp</result> </action> </package> <package name="p2" extends="father"> <action name="testB" class="com.baizhi.action.TestBAction" method="testB"> <result name="ok">/index.jsp</result> </action> </package> </struts>
注意:如果action中显示配置了使用拦截器,那么默认拦截器就失效了
最终问题
配置了自定义拦截器之后,action不能收参了?
struts自动收参的代码,写在了一个拦截器里,被配置在了struts-default包中,配置为默认使用的拦截器
当你在某个action中显示配置使用自定拦截器,默认拦截器就失效了,导致不能收参
解决办法;手动显示的配置使用默认拦截器即可
<package name="p1" extends="father"> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <interceptor-ref name="bInt"></interceptor-ref> struts的默认拦截器 <interceptor-ref name="defaultStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> <action name="b" class="com.baizhi.action.TestAction" method="mb"> <result name="ok">/index.jsp</result> </action> </package>
显示配置了使用拦截器,那么默认拦截器就失效了
最终问题
配置了自定义拦截器之后,action不能收参了?
struts自动收参的代码,写在了一个拦截器里,被配置在了struts-default包中,配置为默认使用的拦截器
当你在某个action中显示配置使用自定拦截器,默认拦截器就失效了,导致不能收参
解决办法;手动显示的配置使用默认拦截器即可
<package name="p1" extends="father"> <action name="a" class="com.baizhi.action.TestAction" method="ma"> <interceptor-ref name="bInt"></interceptor-ref> struts的默认拦截器 <interceptor-ref name="defaultStack"></interceptor-ref> <result name="ok">/index.jsp</result> </action> <action name="b" class="com.baizhi.action.TestAction" method="mb"> <result name="ok">/index.jsp</result> </action> </package>