zoukankan      html  css  js  c++  java
  • spring注解-web

      以往进行web项目开发都需要在web.xml配置servlet、filter、listener,在Servlet3.0可以通过注解的方式配置它们(注意:必须用tomcat7以上版本)

    @WebServlet

    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello...");
        }
    }

    ServletContainerInitializer

      Servlet容器在启动应用的时候会扫描当前应用每一个jar包里面的META-INF/services/javax.servlet.ServletContainerInitializer;我们可以按照规范在项目的类路径下创建一个META-INF/services/并配置名字为javax.servlet.ServletContainerInitializer的文本,内容就是我们实现ServletContainerInitializer接口的全类名,应用启动就会运行这个实现类的方法,通过@HandlesTypes可以传入我们需要的类

    编码的方式添加Web组件(Servlet、Filter、Listener)

      使用ServletContext必须在项目启动的时候注册Web组件,有2种实现方式:ServletContainerInitializer、ServletContextListener接口获取到的ServletContext进行添加

    Filter

    public class UserFilter implements Filter {
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
                throws IOException, ServletException {
            // 过滤请求
            System.out.println("UserFilter...doFilter...");
            //放行
            arg2.doFilter(arg0, arg1);
            
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
            
        }
    
    }

    HttpServlet

    public class UserServlet extends HttpServlet {
        
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // TODO Auto-generated method stub
            resp.getWriter().write("tomcat...");
        }
    
    }

    ServletContextListener

      监听项目的启动和停止

    public class UserListener implements ServletContextListener {
    
        
        //监听ServletContext销毁
        @Override
        public void contextDestroyed(ServletContextEvent arg0) {
            // TODO Auto-generated method stub
            System.out.println("UserListener...contextDestroyed...");
        }
    
        //监听ServletContext启动初始化
        @Override
        public void contextInitialized(ServletContextEvent arg0) {
            // 获取到servletContext进行添加组件
            ServletContext servletContext = arg0.getServletContext();
            System.out.println("UserListener...contextInitialized...");
        }
    
    }

    ServletContainerInitializer

    容器启动的时候,会运行onStartup方法

    @HandlesTypes获取指定的类型下面的子类(实现类,子接口等)传递到arg0中

    ServletContext代表一个Web应用上下文

    @HandlesTypes(value={HelloService.class})
    public class MyServletContainerInitializer implements ServletContainerInitializer {
    
        /**
         * Set<Class<?>> arg0:感兴趣的类型的所有子类型;
         * ServletContext arg1:代表当前Web应用的ServletContext;
         */
        @Override
        public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
            // TODO Auto-generated method stub
            System.out.println("感兴趣的类型:");
            for (Class<?> claz : arg0) {
                System.out.println(claz);
            }
            
            //注册组件  ServletRegistration  
            ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new UserServlet());
            //配置servlet的映射信息
            servlet.addMapping("/user");
            
            
            //注册Listener
            sc.addListener(UserListener.class);
            
            //注册Filter  FilterRegistration
            FilterRegistration.Dynamic filter = sc.addFilter("userFilter", UserFilter.class);
            //配置Filter的映射信息
            filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
            
        }
    
    }

    异步处理

      支持Servlet的异步处理功能须开启asyncSupported=true(开启异步模式)

    @WebServlet(value="/async",asyncSupported=true)
    public class HelloAsyncServlet extends HttpServlet {
        
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("主线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
            AsyncContext startAsync = req.startAsync();
            
         //开始异步处理 startAsync.start(
    new Runnable() { @Override public void run() { try { System.out.println("副线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); sayHello();
                //异步处理完毕 startAsync.complete();
    //获取到异步上下文 AsyncContext asyncContext = req.getAsyncContext(); //获取响应 ServletResponse response = asyncContext.getResponse(); response.getWriter().write("hello async..."); System.out.println("副线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } catch (Exception e) { } } }); System.out.println("主线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } public void sayHello() throws Exception{ System.out.println(Thread.currentThread()+" processing..."); Thread.sleep(3000); } }

    servlet3.0整合springMVC

    • 在spring-mvc.jar里的/META-INF/services/javax.servlet.ServletContainerInitializer记录了org.springframework.web.SpringServletContainerInitializer,上面章节讲过web容器在启动的时候会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer并加载这个文件指定的类
    • 在这个类中标注了@HandlesTypes(WebApplicationInitializer.class),所以在应用启动的时候会加载WebApplicationInitializer接口下的所有组件,并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类);这个组件有三个抽象类:
    • AbstractContextLoaderInitializer:
      • createRootApplicationContext()  //创建根容器
    • AbstractDispatcherServletInitializer:
      • createServletApplicationContext()  //创建web的ioc容器
      • createDispatcherServlet()  //创建DispatcherServlet,将它添加到到ServletContext中
      • getServletMappings()  //servlet映射地址
    • AbstractAnnotationConfigDispatcherServletInitializer  //注解方式配置
      • createRootApplicationContext()      //创建根容器
      • getRootConfigClasses()                  //传入spring的配置类
      • createServletApplicationContext()  //创建web的ioc容器
      • getServletConfigClasses()             //获取配置类

    实现

      以注解方式启动SpringMVC,我们只要继承AbstractAnnotationConfigDispatcherServletInitializer实现抽象方法(指定DispatcherServlet的配置信息)

    public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        //获取根容器的配置类;(Spring的配置文件)   父容器;
        @Override
        protected Class<?>[] getRootConfigClasses() {
            // TODO Auto-generated method stub
            return new Class<?>[]{RootConfig.class};
        }
    
        //获取web容器的配置类(SpringMVC配置文件)  子容器;
        @Override
        protected Class<?>[] getServletConfigClasses() {
            // TODO Auto-generated method stub
            return new Class<?>[]{AppConfig.class};
        }
    
        //获取DispatcherServlet的映射信息
        //  /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
        //  /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
        @Override
        protected String[] getServletMappings() {
            // TODO Auto-generated method stub
            return new String[]{"/"};
        }

      spring容器

    //Spring的容器不扫描controller;父容器
    @ComponentScan(value="com.atguigu",excludeFilters={
            @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
    })
    public class RootConfig {
    
    }

      web容器

    @EnableWebMvc等同于xml配置<mvc:annotation-driven/>
    配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。) extends WebMvcConfigurerAdapter
    //SpringMVC只扫描Controller;子容器
    //useDefaultFilters=false 禁用默认的过滤规则;
    @ComponentScan(value="com.atguigu",includeFilters={
            @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
    },useDefaultFilters=false)
    @EnableWebMvc 
    public class AppConfig  extends WebMvcConfigurerAdapter  {//视图解析器
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            // TODO Auto-generated method stub
            //默认所有的页面都从 /WEB-INF/ xxx .jsp
            //registry.jsp();
            registry.jsp("/WEB-INF/views/", ".jsp");
        }
        
        //静态资源访问
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            // TODO Auto-generated method stub
            configurer.enable();
        }
        
        //拦截器
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // TODO Auto-generated method stub
            //super.addInterceptors(registry);
            registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
        }
    
    }
    public class MyFirstInterceptor implements HandlerInterceptor {
    
        //目标方法运行之前执行
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            // TODO Auto-generated method stub
            System.out.println("preHandle..."+request.getRequestURI());
            return true;
        }
    
        //目标方法执行正确以后执行
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            // TODO Auto-generated method stub
            System.out.println("postHandle...");
    
        }
    
        //页面响应以后执行
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            // TODO Auto-generated method stub
            System.out.println("afterCompletion...");
        }
    
    }

    springmvc异步处理

      springmvc异步处理有两种方式:controller方法返回类型是Callable和DeferredResult

    Callable

    • 在方法返回类型为Callable的时候,将callable对象提交到TaskExecutor,主线程会开启一个隔离的线程进行异步处理,剩余流程继续执行不会等待
    • 方法执行完DispatcherServlet和所有的Filter退出web容器的线程,但是response保持打开状态
    • 当Callable返回结果,SpringMVC将请求又重新派发给容器进行之前的处理,继续进行视图渲染流程等(从收请求-视图渲染)
    @ResponseBody
        @RequestMapping("/async01")
        public Callable<String> async01(){
            System.out.println("主线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
            
            Callable<String> callable = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
                    Thread.sleep(2000);
                    System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
                    return "Callable<String> async01()";
                }
            };
            
            System.out.println("主线程结束..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
            return callable;
        }

      执行流程:HandlerInterceptor的preHandle()-》目标方法,执行完后DispatcherServlet及所有的Filter退出线程-》执行Callable,完成后再次重发请求,拦截器会又一次打印preHandle(),并且剩余的postHandle、afterCompletion依次执行

    DeferredResult

    deferredResult保存到队列中,写个监听器监听这个队列是否变化,如果有就触发create()进行业务处理,从队列拿到DeferredResult并把处理的结果保存回去

       @ResponseBody
        @RequestMapping("/createOrder")
        public DeferredResult<Object> createOrder(){
            DeferredResult<Object> deferredResult = new DeferredResult<>((long)3000, "create fail...");       
            DeferredResultQueue.save(deferredResult);
            return deferredResult;
        }
        
        
        @ResponseBody
        @RequestMapping("/create")
        public String create(){
            //创建订单
            String order = UUID.randomUUID().toString();
            DeferredResult<Object> deferredResult = DeferredResultQueue.get();
            deferredResult.setResult(order);
            return "success===>"+order;
        }

      public class DeferredResultQueue { private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedQueue<DeferredResult<Object>>(); public static void save(DeferredResult<Object> deferredResult){ queue.add(deferredResult); } public static DeferredResult<Object> get( ){ return queue.poll(); } }

    异步的拦截器

    • 原生API的AsyncListener
    • 实现AsyncHandlerInterceptor接口

    同步:request请求-》目标方法运行之前执行拦截器的preHandle()-》目标方法-》目标方法执行正确以后执行拦截器的postHandle()-》页面响应以后执行afterCompletion

    控制器返回Callable

  • 相关阅读:
    高级特性(4)- 数据库编程
    UVA Jin Ge Jin Qu hao 12563
    UVA 116 Unidirectional TSP
    HDU 2224 The shortest path
    poj 2677 Tour
    【算法学习】双调欧几里得旅行商问题(动态规划)
    南洋理工大学 ACM 在线评测系统 矩形嵌套
    UVA The Tower of Babylon
    uva A Spy in the Metro(洛谷 P2583 地铁间谍)
    洛谷 P1095 守望者的逃离
  • 原文地址:https://www.cnblogs.com/edda/p/13497051.html
Copyright © 2011-2022 走看看