7-web应用

Spring boot为Spring mvc 提供的自动配置适用于大多数应用,并引入如下的配置信息:

  1. 引入 ContentNegotiatingViewResolver 和 BeanNameViewResolver beans。
  2. 对静态资源的支持,包括对WebJars的支持。
  3. 自动注册 Converter , GenericConverter , Formatter beans。
  4. 对 HttpMessageConverters 的支持。
  5. 自动注册 MessageCodeResolver 。
  6. 对静态 index.html 的支持。
  7. 对自定义 Favicon 的支持。
  8. 自动使用 ConfigurableWebBindingInitializer bean。
    spring boot为FreeMarker,Groovy,tymeleaf,velocity,mustache提供自动配置,不建议使用jSP,不管使用那种模板引擎都会从/src/main/resources/templates下自动加载模板。
CORS支持

跨域资源请求,Spring mvc对cors提供开箱即用的支持,不用添加任何特殊配置,只需要在spring boot应用的controller类和方法上注解@CrossOrigin,并添加CORS配置。例如,允许controller中定义的所有方法实现跨域请求,如下:

@CrossOrigin(origins = "http://domain.example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

也可以将@@CrossOrigin注解在controller中的方法上,Spring会结合类上的CrossOrigin和方法上的CrossOrigin配置形成完整的CrossOrigin配置,例如:

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin("http://domain1.example.com")
    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

CorsConfiguration可以通过以下三种方式提供自定义设置,
1,AbstractHandlerMapping,通过setCorsConfigurations(Map corsConfigurations)方法,传入一个CorsConfiguration的Map,其中corsConfiguration基于URL pattern.
2,继承AbstractHandlerMapping,重写getCorsConfiguration方法,提供自定义的CorsConfiguration。
3,实现CorsConfigurationSource接口,实现getCorsConfiguration(HttpServletRequest request)方法,为每个请求创建CorsConfiguration实例。

cors 全局配置

使用Javaconfig配置:

@SuppressWarnings("deprecation")
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.example.com","http://domain3.example.com")//添加允许的域
            .allowedMethods("PUT", "DELETE","POST","GET")//添加允许支持的http 方法
            .allowedHeaders("header1", "header2", "header3")//添加允许的header
            .exposedHeaders("header1", "header2") //添加暴漏的本地header
            .allowCredentials(false) //配置是否允许使用证书
            .maxAge(3600);
    }
}

使用XML配置:



    

    

使用Filter:
Spring 提供CorsFilter代替@CorsOrigin注解和WebMvcConfigurer#addCorsMappings(CorsRegistry)。例如:

public class MyCorsFilter extends CorsFilter{

    public MyCorsFilter() {
        super(getMyCorsConfiguration());
    }
    
    private static CorsConfigurationSource getMyCorsConfiguration(){
        
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://domain.example.com");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return source;
    }
}

需要保证CorsFilter注册在所有filter之前。在spring boot中可以按照如下方法实现filter的顺序:

@Bean
    public FilterRegistrationBean corsFilter() {
        
        FilterRegistrationBean bean = new FilterRegistrationBean(new MyCorsFilter());
        bean.setOrder(0);
        return bean;
    }

提供REST Api接口

利用@RestController可以创建基于rest api的函数接口,除此之外Spring提供Jersey 2.x的原生支持,并支持起步配置。添加jersey依赖,


    org.springframework.boot
    spring-boot-starter-jersey

继承ResouceConfig注册service端点,例如:

@Component
public class JerseyConfig extends ResourceConfig{

    public JerseyConfig(){
        register(MyEndPoint.class);
    }
}

创建服务端点:

@Component
@Path("/user")
public class MyEndPoint {

    @Path("/info")
    @GET
    public String getUserInfo(@QueryParam("uid")String uid){
        
        return "success;user uid is "+uid;
    }
    
    @Path("/pwd")
    @GET
    public String getUserPwd(@QueryParam("uid")String uid){
        
        return "success :user pwd is test";
    }
}

运行spring boot应用访问:http://localhost:8080/user/info?uid=zhongzhong,查看返回信息:


在默认情况下jersey的servlet会映射到“/*”,使用@ApplicaitonPath可以更改映射,例如在JerseyConfig上添加如下注解:

@ApplicationPath("/jersey")

再次运行程序:



通过实现org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer接口,自定义ResourceConfig。

@Component
public class JerseyCustom implements ResourceConfigCustomizer{

    @Override
    public void customize(ResourceConfig config) {
        // TODO Auto-generated method stub
        config.packages("com.zhongzhong.demo.jersey");
        //config.register(MyEndPoint.class);
    }
}

服务端点不变,在Spring boot启动类中添加ResourceConfig配置

    @Bean
    public ResourceConfig getJerseyCustom(){
        
        return new ResourceConfig();
    }

启动程序运行结果相同。在自定义resouceConfig中可以通过ResourceConfig.packages(...)和ResouceConfig.register(...)将服务端点所在包和服务端点注册到ResouceConfig中。但是jersey对扫描可执行archives的支持相当有限。例如, 在运行可执行 war 文件时, 它无法扫描在 WEB INF/classes中找到的包中的服务端点。为避免此限制, 不应使用package方法, 并且应使用register方法单独注册端点。

内嵌servlet支持

Spring boot 内嵌Tomcat,jetty和undertow服务器。在centos上使用内嵌tomcat时会用于程序在运行过程中会删除tmpwatch目录而倒是程序发生错误,所以要重新配置tmpwatch目录来避免。
在使用内嵌servlet时,可以通过使用Spring beans或则Servlet组件的方式注册serlvet,Filters及特定Servlet相关的所有listeners。
如果上下文中只包含一个Servlet,他将被映射到“/”;如果存在多个Servlet,每个Servlet的名称将为被用作路径的前缀,过滤映射到“/*”。还可以使用ServletRegistrationBean、FilterRegistrationBean、ServeltListenerRegistrationBean实现完全的控制。

注册servlet

创建测试Servlet实现javax.servlet.Servlet接口,如下:

public class MyServletTest implements Servlet{
         .....//其他方法省略
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        HttpServletResponse response = (HttpServletResponse) arg1;
        response.getWriter().write("this is MyServlet test");
        response.getWriter().flush();
    }
}

public class MyServlet implements Servlet{
        // 省略其他方法....
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        HttpServletResponse response = (HttpServletResponse) arg1;
        response.getWriter().write("this is MyServlet");
        response.getWriter().flush();
    }
}

在启动类中注入两个org.springframework.boot.web.servlet.ServletRegistrationBean实例,如下:

    @Bean
    public ServletRegistrationBean getServlet(){
        
        ServletRegistrationBean bean = new ServletRegistrationBean();
        bean.addUrlMappings("/myServlet");
        bean.setServlet(new MyServlet());
        bean.setOrder(4);
        return bean;
    }

    @Bean
    public ServletRegistrationBean getServletRegistrationBean(){
        
        ServletRegistrationBean bean = new ServletRegistrationBean();
        bean.addUrlMappings("/myServletTest");
        bean.setServlet(new MyServletTest());
        bean.setOrder(2);
        return bean;
    }

启动应用程序,分别访问:http://localhost:8080/myServlet,http://localhost:8080/myServletTest。


7-web应用_第1张图片

Filter的定义和使用与Servlet相似。定义两个Filter均继承javax.servlet.Filter,例如:

public class MyFilterTest implements Filter{
       //另外两个方法省略
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest)arg0;
        if(request.getRequestURI().endsWith("Test")){
            System.out.println("in "+this.getClass().getName());
            arg2.doFilter(arg0, arg1);
        }else{
            
            System.out.println("request not in my filter");
        }
    }
}

public class MyFilter implements Filter{
        //另外两个方法省略
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest)arg0;
        if(request.getRequestURI().contains("myServlet")){
            System.out.println("in "+this.getClass().getName());
            arg2.doFilter(arg0, arg1);
        }else{
            
            System.out.println("filter not configured in main");
        }
    }
}

在启动类中添加两个org.springframework.boot.web.servlet.FilterRegistrationBean实例,如下:

    @Bean
    public FilterRegistrationBean getMyFilter(){
        
        FilterRegistrationBean myFilter = new FilterRegistrationBean();
        Collection url = new LinkedList();
        url.add("/myServlet");
        myFilter.setFilter(new MyFilter());
        myFilter.addServletNames("myServlet");
        return myFilter;
    }
    @Bean
    public FilterRegistrationBean getMyFilterTest(){
        
        FilterRegistrationBean myFilter = new FilterRegistrationBean();
        Collection url = new LinkedList();
        url.add("/myServletTest");
        myFilter.setFilter(new MyFilterTest());
        myFilter.addServletNames("myServletTest");
        return myFilter;
    }

继续访问http://localhost:8080/myServletTest,控制台输出:

7-web应用_第2张图片

访问 http://localhost:8080/myServlet
7-web应用_第3张图片

自定义内嵌Servlet

在application.properties中设置关于内嵌servlet的配置:
监听地址设置:server.address=8090;
session是否持久化设置:server.session.persistence=true/false;
session超时时间:server.session.timeout=3600;
session数据存放位置:server.session.store-dir=/usr/db/sessiondb
session-cookie设置等(server.session.cookie.*)
编程实现--实现WebServerFactoryCustomizer接口

@Component
public class MyServletCustom implements WebServerFactoryCustomizer{

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        // TODO Auto-generated method stub
        factory.setPort(8090);
    }
}

启动应用程序,端口已更改为8090:



直接初始化ConfigurableServletWebServerFactory,在启动类中添加如下内容:

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.setPort(9000);
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
        return factory;
    }

启动应用程序,端口被更改为9000:


7-web应用_第4张图片

在使用内嵌servlet时,容器对jsp的支持会有一些限制:
1,tomcat只支持war的打包方式,不支持jar;
2,jetty只支持war的打包方式;
3,undertow不支持JSP;
4,创建自定义的error.jsp页面不会覆盖error handling视图。

你可能感兴趣的:(7-web应用)