Struts2 第一讲 -- Struts2开发前奏
我们在学习Struts之前,先来复习一下Servlet,众所周知Servlet是JavaWeb的三大组件。我们发送一个请求,这个请求交给Servlet处理,Servlet将处理的结果返还给浏览器。每个Servlet对应一个URL-pattern。那么有没有这么一种情况呢?我们访问多个URL-pattern,这些URL-pattern具有共同的功能,那就是转发到其它页面,但是又不想写那么多Servlet,Servlet虽然是单例的,但是能少一个对象,对于JVM也是一种优化不是吗,那么有什么办法可以做到呢?如下图
熟悉Servlet的前辈,可能一看就会知道只是不可能的,一个Servlet只能对应一个URLPattern,那么怎么实现这个功能呢?下面我们通过项目来实现一下:
- 创建Web项目struts2_1
- 创建test.jsp页面,在页面中建立三个URL请求链接
<body> <h3>入门路径:</h3><br> <a href="${pageContext.request.contextPath }/UserServlet">userWorld</a><br> <a href="${pageContext.request.contextPath }/HelloServlet">helloWorld</a><br> <a href="${pageContext.request.contextPath }/CustomerServlet">addWorld</a><br> </body>
- 我们首先通过传统的Servlet来实现:
UserServlet
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); System.out.println("欢迎访问UserServlet"); //pw.println("访问一次,我就得写一个Servlet!!!");请求转发会将response携带的数据丢失 request.getRequestDispatcher("/success.jsp").forward(request, response); pw.flush(); pw.close(); }
Web.xml <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>cn.web.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping>
@WebServlet("/HelloServlet") public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); System.out.println("欢迎访问HelloServlet"); pw.println("访问一次,我就得写一个Servlet!!!!"); request.getRequestDispatcher("/error.jsp").forward(request, response); pw.flush(); pw.close(); }
@WebServlet("/CustomerServlet") public class CustomerServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); System.out.println("欢迎访问CustomerServlet"); pw.println("访问一次,我就得写一个Servlet!!!!!"); request.getRequestDispatcher("/add.jsp").forward(request, response); pw.flush(); pw.close(); }
Success.jsp <body> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx </body>
Error.jsp <body> 错误页面 </body>
Add.jsp <body> 添加 </body>
我们在浏览器访问test.jsp,然后可以访问到这些Servlet,但是我们也注意到了,每一个URLpattern对应一个Servlet,这么多请求造成了我们写了很多Servlet,并且需要很多web.xml中的配置(Servlet3.0以后支持注解)。 那么能否实现在web容器中只配置一次,就可以实现以上3个URL都可以跳转到指定的页面呢?
结论:可以使用过滤器实现:我们在过滤器中过滤所有的请求,进行判断,如果是test.jsp那么放行,否则就全部过滤操作。实际上根据上图我们知道这样一个对应关系,那就是一个请求对应一个Servlet,然后一个Servlet对应一个页面,那么我们创建两个Map集合,一个放请求和类的对应,一个放返回值和页面的对应.
- 创建一个Action接口,作为请求对应的类,它有三个实现类对应三个Servlet
package cn.filter;
public interface Action {
public String excute();
}
package cn.filter; public class HelloAction implements Action{ @Override public String excute() { System.out.println("访问HelloAction!"); return "error"; } }
package cn.filter; public class UserAction implements Action { @Override public String excute() { System.out.println("访问UserAction!"); return "success";//对应请求转发的页面名称 } }
package cn.filter; public class CustomerAction implements Action { @Override public String excute() { System.out.println("访问CustomerAction!"); return "add"; } }
- 创建Filter,然后对过滤进行操作
package cn.filter; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebFilter( dispatcherTypes = {DispatcherType.REQUEST } , urlPatterns = { "/TestFilter", "/*" }) public class TestFilter implements Filter { //使页面的访问路径对应Action类 Map<String, String> actionMap = new HashMap<>(); //使对应的action返回值对应相应的jsp页面 Map<String, String> returnMap = new HashMap<>(); //web容器启动时执行 public void init(FilterConfig fConfig) throws ServletException { actionMap.put("/UserServlet", "cn.filter.UserAction"); actionMap.put("/HelloServlet", "cn.filter.HelloAction"); actionMap.put("/CustomerServlet", "cn.filter.CustomerAction"); returnMap.put("success", "/success.jsp"); returnMap.put("add", "/add.jsp"); returnMap.put("error", "/error.jsp"); } public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request= (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //获取请求Servlet路径 String path = request.getServletPath(); if(path != null && path.equals("/test.jsp")){ chain.doFilter(request, response); return; }//如果是test.jsp那么放行 //如果不是test.jsp页面,那就进行过滤操作 //获取访问的action路径 String actionClass = actionMap.get(path); try { //通过反射获取Action类的对象 Action action = (Action) Class.forName(actionClass).newInstance(); //获取返回的页面名称 String returnValue = action.excute(); //利用Action类的返回值,获取所对应的页面 String page = returnMap.get(returnValue); //转发到相应页面 request.getRequestDispatcher(page).forward(request, response); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
我们使用浏览器进行测试,发现,这次我们的请求没有经过Servlet,而是通过Action类处理了(对比前后两次控制台打印输出可以看出),通过过滤器,我们简单避免了web.xml中的反复配置.上面其实就是一个简单的Struts2实现: