目录:
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有两种方法:代码注册和注解自动注册。
-
代码注册通过
ServletRegistrationBean
、FilterRegistrationBean
和ServletListenerRegistrationBean
获得,也可以通过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。
这里顺便提一下监听器和过滤器的启动顺序,在系统启动时,监听器最先初始化,因此先调用MyServletContextListener
的contextInitialized
方法。另一个监听器是创建session用的,因此在访问页面(并显式调用getSession)时调用。
过滤器在监听器之后初始化,初始化时调用init
方法,在访问页面时调用doFilter
方法。而销毁时则相反,后初始化的先销毁。
4. Interceptor
拦截器作用和过滤器有点类似,但区别也是很明显的。过滤器是在Servlet中定义的,而拦截器是在spring中定义的,两者属于不通的规范。
过滤器在web容器初始化过程中初始化,在web请求到达服务器之前进行过滤。而拦截器是随着spring容器初始化而进行初始化的,在请求到达DispatcherServlet
之后进行拦截。
拦截器中有三个方法,preHandle
在request
请求被响应之前执行,postHandle
在request
请求被响应之后,视图渲染之前执行,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/