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