servlet的缺点
1、 在web.xml文件中需要配置很多行代码,维护起来很不方便,不利于团队合作
2、 一个servlet的入口只有一个doPost或者doGet方法,如果在一个servlet中写好几个方法,怎么办?
这样会导致代码结构很乱
3、 servlet类与servlet容器高度耦合,每个方法中都有两个参数request,response。如果服务器不启动,这两个参数没有办法初始化。
4、 如果在servlet中的一个方法中,有很多功能,这个时候,会导致该方法比价复杂,以致于不利于维护
用户注册完成了4件事情,所以整个方法比较杂乱
5、 如果一个servlet类中有很多方法,浏览器对这些方法进行请求,url写起来很麻烦
6、在servlet中如果要获取页面上表单中的数据,那么在方法中会写很多行
servlet重构
目的
1、 在web.xml文件中只写一个过滤器
2、 用action处理业务逻辑
3、 在过滤器中动态的调用action中的方法处理业务逻辑
设计
1、 监听器
1、 准备一个map
2、 把所有的action的key,value放入到map中
3、 把map放入到application域中
2、 过滤器
1、 获取application域中的map
2、 解析url
3、 根据解析的url从map中把value提取出来
4、 根据java的反射机制动态调用action
5、 根据action返回的方法跳转到相应的页面
3、执行action 的execute方法,该方法返回一个字符串
实现
<?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"> <listener> <listener-class>com.itheima09.servlet.listener.ServletListener</listener-class> </listener> <filter> <filter-name>actionFilter</filter-name> <filter-class>com.itheima09.servlet.filter.DispatcherFilter</filter-class> </filter> <filter-mapping> <filter-name>actionFilter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> </web-app>
package com.itheima09.servlet.listener; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class ServletListener implements ServletContextListener{ /** * 在tomcat销毁的时候执行 */ @Override public void contextDestroyed(ServletContextEvent arg0) { arg0.getServletContext().setAttribute("mappings", null); } /** * 在tomcat启动的时候执行 */ @Override public void contextInitialized(ServletContextEvent arg0) { Map<String, String> map = new HashMap<String, String>(); map.put("userAction", "com.itheima09.action.UserAction"); arg0.getServletContext().setAttribute("mappings", map); } }
package com.itheima09.servlet.filter; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.itheima09.servlet.utils.ServletUtils; public class DispatcherFilter implements Filter{ private ServletContext servletContext; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { /** * 1、从 application域中获取map */ HttpServletRequest request = (HttpServletRequest)arg0; HttpServletResponse response = (HttpServletResponse)arg1; Map<String, String> map = (HashMap<String, String>)this.servletContext.getAttribute("mappings"); /** * 2、获取浏览器中的url,把url解析出来 * http://localhost:8080/itheima09_servlet_super/userAction.action * ---->userAction */ //mapping = userAction String mapping = ServletUtils.parse(request.getRequestURI()); String value = map.get(mapping); //value就是action的类的全名 try { Class class1 = Class.forName(value); Method method = class1.getMethod("execute", HttpServletRequest.class,HttpServletResponse.class); //调用了action中的方法 String jspName = (String)method.invoke(class1.newInstance(), request,response); request.getRequestDispatcher(jspName).forward(request, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub this.servletContext = arg0.getServletContext(); } }
package com.itheima09.servlet.utils; import org.junit.Test; public class ServletUtils { /** * http://localhost:8080/itheima09_servlet_super/userAction.action * @param url * @return */ public static String parse(String url){ String[] array = url.split("/"); String mapping = array[array.length-1].substring(0,array[array.length-1].indexOf(".")); return mapping; } @Test public void test(){ System.out.println(ServletUtils.parse("http://localhost:8080/itheima09_servlet_super/userAction.action")); } }
struts历史
1、 servelet
2、 struts1
1、 写action
2、 写了一个中控的servlet
3、 actionForm 和页面上表单中的内容一致
3、webwork
1、使得action与servlet容器完全松耦合
2、属性驱动和模型驱动获取页面上表单中的数据
3、利用了拦截器的概念把servlet容器的第4个缺点克服掉了
4、struts1+webwork=struts2
struts2第一个例子
解析
struts.xml文件
注意:
1、 struts.xml文件必须放在classpath的根目录下
2、 名字必须为struts.xml文件
3、 因为整个加载过程写在了过滤器中的init方法中,所以tomcat启动的时候就把该文件加载了
package
1、 用意:用来管理action的
2、 name属性 为包的名称,是唯一的
3、 namespace 为命名空间,是针对url的
4、 extends 包的继承
在tomcat启动的时候,不仅加载了struts.xml文件,而且还加载了struts-default.xml文件,而这个文件在classpath下。针对该文件的路径在
package 可以被其他package包通过extend继承
在一个配置文件中:
说明helloworld拥有package的名称为struts-default包的所有的功能
同样 包可以再被继承
action
action元素代表一个类
class为action的类的全名,可以写,也可以不写
如果不写class属性,则默认执行ActionSupport中的execute方法
该方法什么都没有做,仅仅返回了一个success字符串
如图:
result
代表一种结果集
Type 为结果集的类型
Name 属性的值和action中某一个方法的返回值一致
type属性不写,则默认和struts-default中的结果集中的default="true"的结果集保持一致
为dispatcher,转发
result标签中的内容就是要转发到的页面
在struts-default.xml文件中
Name属性也可以不写,如果不写,则默认值为”success”
Struts2基本用法的其他方法
Include
Action的写法
1简单javabean
2.实现Action接口
重写execute方法
3.继承SupportAction
验证功能 国际化功能 validate方法
Action的模式
在action的构造器中输出一句话,在浏览器中多次请求,可以看到构造器执行了好几次,所以action是多例的。
结果集
转发
重定向
重定向到action
通配符映射
第一种
第二种
缺点:action中有几个方法就得在配置文件中写几个action元素
第三种
方法的动态调用
第四种
第五种
该模型的好处:如果在action中增加了一个方法,配置文件是不需要改变的,在写url时
urlPatternAction_后面的内容变成要请求的方法的名称就可以了
第六种
第七种
不推荐
第八种
强制让url中的_后面的内容和方法保持一致,跳转到的jsp页面的名称和方法的名称也保持一致。这么写带有一定的规范性
Struts2与servlet容器的交互
1.
这种方法可以交互,但是这种方法把ServletAction与servlet容器耦合性变高了,不利于测试。
2.可以通过ServletActionContext把servlet容器相关的类调出来
总结
1、 sturts2的配置文件中用了package的机制,这样可以分模块
name是唯一的名称,extends采用了继承的机制
2、 写的action与servlet容器完全松耦合了
3、 通配符映射解决:很容器就把一个url映射到一个action的方法中了
4、 Include保证了可以写多个配置文件
5、 结果集的封装