SpringBoot基础(1)

目录:
SpringBoot基础(1)
SpringBoot基础(2)
SpringBoot基础(3)

1. hello world

相当简单,pom.xml文件中配置(请根据实际情况更新springboot版本):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.2</version>
</parent>

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

SpringBootSampleApplication类如下:

@SpringBootApplication
public class SpringBootSampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleApplication.class,args);
    }
}

然后就是controller中的rest接口了:

@RestController
@RequestMapping("/hello")
public class HelloController {
    @RequestMapping
    public String hello() {
        return "Hello Spring-Boot";
    }
}

运行main函数,直接通过内置的tomcat就发布了web程序。

通过8080端口可以访问:http://localhost:8080/hello

几分钟内就搭建了一个web应用,省去了配置web.xml,springmvc.xml等文件的麻烦,大大节省了时间。需要注意的一点是,SpringBootSampleApplication要放在顶层包中,这就是约定大于配置的规则。

可以看到,controller中的注解不是用的@Controller,而是@RestController,该注解是sprig4.0引入的,包含了@Controller@ResponseBody,是两者的合二为一,因此也不需要加@ResponseBody注解,就可以直接响应json结果。

parent配置表示当前pom文件从spring-boot-starter-parent继承下来,在spring-boot-starter-parent中提供了很多默认的配置,这些配置可以大大简化我们的开发。

2. Servlet

使用Spring Boot时,嵌入式servlet容器(也就是内置的tomcat)通过扫描注解的方式注册Servlet、Filter和Listener。

Spring Boot的主Servlet为DispatcherServlet,默认的url-pattern为/

在Spting Boot中添加自己的servlet/filter/linstener有两种方法:代码注册注解自动注册

  • 代码注册通过ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean获得,也可以通过ServletContextInitializer接口直接注册。

  • 注解方式注册是在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener 可以直接通过@WebServlet@WebFilter@WebListener注解自动注册。

代码方式注册

在SpringBootSampleApplication中添加:

/**
 * 使用代码方式注册servlet
 */
@Bean
public ServletRegistrationBean xsServlet() {
    return new ServletRegistrationBean(new XsServlet(), "/xs/*");
}

注册的Servlet:

public class XsServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
        resp.setContentType("text/html");  
        PrintWriter out = resp.getWriter();  
        out.println("<html>");  
        out.println("<head>");  
        out.println("<title>Hello World</title>");  
        out.println("</head>");  
        out.println("<body>");  
        out.println("<h1>大家好,我的名字叫Servlet</h1>");  
        out.println("</body>");  
        out.println("</html>"); 
    }
}

该servlet拦截*/xs/*的请求,并通过out对象输出信息。

当然,servlet/filter/listener的注册也可以写在注解了Configuration的类中。如下:

@Configuration
public class ServletRegister {
    /**
     * 使用代码方式注册servlet
     */
    @Bean
    public ServletRegistrationBean xsServlet() {
        return new ServletRegistrationBean(new XsServlet(), "/xs/*");
    }
}

Configuration即相当于spring的xml配置文件。标注了@Bean的方法,其返回值将作为一个bean注册到Spring的IoC容器,如果不定义名字,方法名将默认成该bean定义的id。返回的类型即为注册bean的类型。

注解方式注册

SpringBootSampleApplication上添加@ServletComponentScan注解,在MyServlet类上加上@WebServlet(urlPatterns = "/xs")注解即可。filter和listener注册同理。

刚刚说过,在DispatcherServlet中默认拦截“/”,但是可以修改拦截路径。
SpringBootSampleApplication中添加代码:

@Bean
public  ServletRegistrationBean  dispatcherRegistration(DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
    registration.getUrlMappings().clear();
    registration.addUrlMappings("*.do");
    registration.addUrlMappings("*.json");
    return registration;
}

修改之后访问地址必须同时满足requestMapping映射的url和后缀为do或者json,才能返回对应视图。

3. Filter和Listener

过滤器和监听器的注册跟servlet类似,也是通过代码注册和注解自动注册。代码注册就不说了,注解自动注册先在SpringBootSampleApplication上添加@ServletComponentScan注解,并在过滤器类上添加@WebFilter注解:

@WebFilter
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行过滤操作");
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("过滤器初始化");
    }
}

如果默认请求了网页图标favicon.ico,则会执行两次过滤,可以对favicon.ico请求不执行过滤:

HttpServletRequest httpServletRequest=(HttpServletRequest) request;  if(!httpServletRequest.getRequestURI().contains("favicon.ico")) {
      System.out.println("执行过滤操作");
      filterChain.doFilter(request, response); 
 }

注意,通过@WebFilter添加的filter执行是没有顺序的,如果需要指定顺序,可以通过代码注册或者继承Filter接口。可参考过滤器执行顺序问题分析

在监听器类上添加@WebListener注解:

@WebListener
public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContex初始化");
        System.out.println(sce.getServletContext().getServerInfo());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContex销毁");
    }

}

另一个监听器:

@WebListener
public class MyHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("Session 被创建");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Session销毁");
    }
}

在启动时可以看到输出:

ServletContex初始化
Apache Tomcat/8.0.30
过滤器初始化

访问页面输出:

执行过滤操作

这里为什么session创建没有被监听到?这是因为session创建必须在显式调用的时候才会创建。即HttpServletRequest的getSession方法才会触发sessionCreated。

这里顺便提一下监听器和过滤器的启动顺序,在系统启动时,监听器最先初始化,因此先调用MyServletContextListenercontextInitialized方法。另一个监听器是创建session用的,因此在访问页面(并显式调用getSession)时调用。

过滤器在监听器之后初始化,初始化时调用init方法,在访问页面时调用doFilter方法。而销毁时则相反,后初始化的先销毁。

4. Interceptor

拦截器作用和过滤器有点类似,但区别也是很明显的。过滤器是在Servlet中定义的,而拦截器是在spring中定义的,两者属于不通的规范。

过滤器在web容器初始化过程中初始化,在web请求到达服务器之前进行过滤。而拦截器是随着spring容器初始化而进行初始化的,在请求到达DispatcherServlet之后进行拦截。

拦截器中有三个方法,preHandlerequest请求被响应之前执行,postHandlerequest请求被响应之后,视图渲染之前执行,afterCompletion在视图渲染之后执行。

在SpringBoot中实现自定义拦截器只需要3步:

  • (1)创建自己的拦截器实现类,并实现HandlerInterceptor接口(或者继承HandlerInterceptorAdapter类)。
  • (2)创建一个Java类继承WebMvcConfigurerAdapter,并重写addInterceptor方法。
  • (3)将自定义拦截器添加到拦截器链中。

示例如下:

public class MyInterceptor1 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");

        return true;// 只有返回true才会继续向下执行,返回false取消当前请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
    }

}

注册拦截器:

@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
        /*registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");*/
    }
}

注册第二个过滤器,执行后结果如下:

>>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)
>>>MyInterceptor2>>>>>>>在请求处理之前进行调用(Controller方法调用之前)
>>>MyInterceptor2>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
>>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)

>>>MyInterceptor2>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
>>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)

可以看到两个过滤器的不同方法的执行顺序。

只有经过DispatcherServlet 的请求,才会走拦截器链,自定义的Servlet 请求是不会被拦截的,比如自定义的xsServlet 是不会被拦截器拦截的。并且不管是属于哪个Servlet,只要符合过滤器的过滤规则,过滤器都会拦截。

最后说明下,上面用到的 WebMvcConfigurer 并非只是注册添加拦截器使用,其顾名思义是做Web配置用的,它还可以有很多其他作用。

参考资料

[1].http://blog.csdn.net/catoop/article/details/50501664/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值