不学无数—SpringBoot入门V

SpringBoot入门V

Posted by 不学无数 on September 5, 2018

SpringBoot

1.开发一个Web程序

SpringBoot是非常适合开发Web应用的,因为他内嵌有Tomcat、Jetty、Undertow或者Netty。大部分的应用可以通过加载spring-boot-starter-web模块能够快速的创建并启动一个Web应用。

1.1SpringMVC框架

SpringMVC是一个“model view controller”的Web级的框架。SpringMVC能够用@Controller或者@RestController注解在Bean中拦截相应的HTTP请求。具体请求方法是在用@Controller或者@RestController进行注解的类中的方法里面。方法用@RequestMapping进行注解。下面的例子展示了典型的@RestController的使用方法。

@RestController
@RequestMapping(value="/users")
public class MyRestController {

	@RequestMapping(value="/{user}", method=RequestMethod.GET)
	public User getUser(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
	List<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
	public User deleteUser(@PathVariable Long user) {
		// ...
	}

}

Spring MVC是Spring框架的一部分,详细的信息可以看SpringMVC官方文档

1.1.1 SpringMVC自动配置

SpringMVC不用再像之前一样用许多的配置文件来开启各种功能,SpringBoot已经将其许多的功能进行了自动配置化。下面就是SpringBoot针对SpringMVC的自动配置的一些功能:

  • 包括ContentNegotiatingViewResolver和BeanNameViewResolver类
  • 支持静态资源的服务,包括支持WebJars
  • 自动注册Converter、GenericConverter和Formatter
  • 支持HttpMessageConverters
  • 自动注册MessageCodesResolver
  • 支持静态的index.html
  • 对于定制化Favicon的支持
  • 自动使用ConfigurableWebBindingInitializer

如果你想保持上面的功能不变,但是想要额外的添加一些功能。能够使用@Configuration注解进行配置不能加上@EnableWebMvc,如果你不想要上面的功能,想完全自己定义SpringMVC的功能,那么就加上@EnableWebMvc。如果想要拥有定制化的RequestMappingHandlerMapping、RequestMappingHandlerAdapter或者ExceptionHandlerExceptionResolver,声明一个WebMvcRegistrationsAdapter实例提供相应的内容。

1.1.2 HttpMessageConverters

SpringMVC使用HttpMessageConverter去转换从HTTP发出来的请求及响应的内容。HTTP的请求其实都会封装在ServletInputStream流中,而响应则会封装在ServletOutputStream流中。而从流中读取的数据都是原始的字符串的报文,此时就需要将报文进行转换。而基本上都是字符串和java对象进行互转的过程。所以SpringMVC用到了HttpMessageConverter来进行解决的。

例如现在有一个实体类User,我直接返回页面UserDao对象。

@RequestMapping("/user")
    UserDao getUser(){
        return new UserDao("不学无数",23,"HeNan","1111111");
    }

此时在访问的时候就会在页面发现对象被转换成了Json字符串

如果需要自己定制转化器的话,可以在SpringBoot使用HttpMessageConverters进行配置,如下所示:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

	@Bean
	public HttpMessageConverters customConverters() {
		HttpMessageConverter<?> additional = ...
		HttpMessageConverter<?> another = ...
		return new HttpMessageConverters(additional, another);
	}
}

1.1.3 定制JSON的序列化和反序列化

如果使用Jackson去序列化和反序列化JSON数据的话,可能需要自己定制JsonSerializer和JsonDeserializer的类。SpringBoot提供了@JsonComponent注解可以直接非常容易的将你写的定制化解析JSON的类注册在Spring中。

也可以使用@JsonComponent直接注解在JsonSerializer和JsonDeserializer的实现上。也可以注解在类上,类中包含了JsonSerializer和JsonDeserializer的实现.如下所示:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

	public static class Serializer extends JsonSerializer<SomeObject> {
		// ...
	}

	public static class Deserializer extends JsonDeserializer<SomeObject> {
		// ...
	}

}

1.1.4 静态资源

默认情况下,SpringBoot会将放在/static、/public、/resources或者/META-INF/resources目录下的文件称为静态资源。因为SpringBoot默认配置的映射地址为/**。例如我们在项目中resources中创建一下两个文件夹,并且将静态的图片资源放入,分别起名为a和b。

此时我们如果将项目启动起来,然后在浏览器中分别访问一下地址

http://localhost:8080/a.png
http://localhost:8080/b.png

都能够正常访问到相应的图片资源。因此可以知道SpringBoot在访问静态资源的时候会从/static、/public、/resources或者/META-INF/resources目录下进行寻找文件,如果找到的话便直接返回。

如果默认的静态资源访问路径不符合需求的话,也可以进行自定义静态资源的访问路径配置。第一种的配置方式就是通过spring.mvc.static-path-pattern元素的配置。此时如果如下配置

##这里表示在页面的访问路径中为/resources/**的时候才会处理请求
spring.mvc.static-path-pattern=/resources/**

那么还是之前的静态资源存放路径的情况下,浏览器得如下访问才能访问到文件。

http://localhost:8080/resources/a.png
http://localhost:8080/resources/b.png

如果此时是想更改静态资源文件的存放路径,那么可以通过spring.resources.static-locations元素进行配置

##默认情况下SpringBoot会在以下的文件夹中寻找静态文件
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources

所以“spring.mvc.static-path-pattern”用于阐述HTTP请求地址,而“spring.resources.static-locations”则用于描述静态资源的存放位置。

第二种方式是通过@Configure注解然后继承WebMvcConfigurerAdapter重写addResourceHandlers方法。

/**
 * @program: FirstSpringBoot
 * @description: 配置静态资源的映射
 * @author: hu_pf@suixingpay.com
 * @create: 2018-07-27 14:37
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/");
    }
}

1.1.5 模板文件

在网络传输中,想要提升效率,第一个是提升网络带宽,第二个就是在有限的带宽下传输更少的东西,而模板文件就是这样。通常在用户第一次访问网站的时候,如果一些不变的内容可以在用户本机生成一个模板文件,然后第二次访问或者刷新的时候只传输动态的内容即可。

SpringBoot支持下列的模板技术的自动配置:

  • FreeMarker
  • Groovy
  • Thymeleaf
  • Mustache

如果使用SpringBoot的默认配置的话,那么模板文件将会自动扫描放在src/main/resources/templates的文件作为模板文件。

如果使用IDEA进行项目的开发的话,由于IDEA扫描路径的方式不同。所以如果使用IDE进行main方法的启动和使用gradle或者maven进行jar包的启动的话,扫描路径也是不同的。这有可能造成SpringBoot在classpath中去找不到templates文件。如果有这种问题的话,可以使用IDEA中的配置资源文件配置一下,或者在配置文件中配置classpath*:/templates/即可。

1.1.6 错误处理

通常在开发过程中,在Controller中每个方法或许都得写一个异常处理的代码。例如下面这个例子:

    @RequestMapping(value = "/query", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> queryCondition() {

        try {
            //业务代码省略
            return setResult(list, count);
        } catch (Exception e) {
            return setFailure("查询失败");
        }
    }

    @RequestMapping(value = "/getDetail", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getByKey() {

        try {
            //业务代码省略
            return map;
        } catch (Exception e) {
            return setFailure("查询失败");
        }
    }

代码中存在着许多的try-catch 而且处理的还都是一个异常,返回的信息也是一样的,所以这时代码就会显得难看而且臃肿。SpringBoot提供了全局的异常处理方法。例如下面例子

/**
 * @program: FirstSpringBoot
 * @description: 全局Controller层异常处理
 * @author: hu_pf@suixingpay.com
 * @create: 2018-07-27 16:54
 **/
@ControllerAdvice
public class GlobExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleException(Exception e){
        return "Exception BuXueWuShu "+e.toString();
    }
}

其中@ControllerAdvice注解是将所写的类注册到Spring容器中,@ControllerAdvice有个参数basePackageClasses,如果写了的话那么他就会处理所写的那个类所传出来的异常。如果不写的话,那么默认处理所有传出来的异常。另外@ExceptionHandler注解里面加上了异常的种类的话,那么此方法就单独的处理所写的异常,如果没写的话,就默认处理所有的异常。这时候在Controller层中所有的try-catch就可以去掉了。

1.1.7 自定义错误页面

在网站中,如果没有找到某个资源的话就会返回404的错误,默认的404界面有点丑,不够美观。如果想要自定义错误页面的话,那么就在静态资源文件夹下创建一个error文件夹,error文件夹下放想要处理状态码的文件,其中文件名为状态码。下面为状态码为404的例子:


src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

当然你也可以和上一节相结合,将错误信息返回到错误页面中,然后运用模板技术将错误信息拼接返回给用户。

1.1.8 自定义内嵌的Servlet容器

通用的Servlet的配置可以通过Spring的环境变量来设置,一般都是讲配置写在application.properties中的。

常见的配置如下:

  • 默认的端口是8080,如果想改变端口号可以通过server.port改变。接口地址绑定server.address
  • session设置:session是否一直保存,server.servlet.session.persistence。session过期时间server.servlet.session.timeout。本地的session数据存放地址:server.servlet.session.store-dir。session-cookie的配置:server.servlet.session.cookie.*
  • error页面的存放地址:server.error.path

ServerProperties 更加详细的配置属性

1.1.8.1 程序化配置

如果想要程序化配置内嵌的Servlet容器的话,需要在Spring中注册实现了WebServerFactoryCustomizer接口的Bean。WebServerFactoryCustomizer提供了ConfigurableServletWebServerFactory。而ConfigurableServletWebServerFactory提供了许多的set方法进行设置属性。例子如下:

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	@Override
	public void customize(ConfigurableServletWebServerFactory server) {
		server.setPort(9000);
	}

}

1.1.8.2 直接配置ConfigurableServletWebServerFactory

如果上面的例子还不满足的话,那么可以直接在Spring容器中注册TomcatServletWebServerFactory、JettyServletWebServerFactory或者UndertowServletWebServerFactory

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

1.1.9 JSP的局限性

SpringBoot是不推荐在项目中使用JSP的,因为JSP在SpringBoot有以下的缺点:

  • Tomcat和Jetty如果使用war进行打包,然后用java -jar进行执行的时候都可以运行的,但是JSPs不支持。
  • Undertow不支持JSPs
  • 创建error.jsp不会覆盖掉默认的错误页面

这有一个JSP Sample教你如何在SpringBoot配置JSP