Spring Boot 对 Web 开发的支持很全面,包括开发、测试和部署阶段都做了支持。spring-boot-starter-web 是 Spring Boot 对 Web 开发提供支持的组件,主要包括 RESTful,参数校验、使用 Tomcat 作为内嵌容器等功能。
JSON的支持
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。JSON 采用完全独立于语言的文本格式,但是也使用了类似于 C 语言家族的习惯(包括 C、C++、C#、Java、JavaScript、Perl、Python 等),这些特性使 JSON 成为理想的数据交换语言。Spring Boot 体系中,对 JSON 支持简单而又完善,在 Web 层使用仅仅只需要一个注解即可完成。
新建一个 spring-boot-web 项目,在 pom.xml 中添加 Web 依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在项目根路径下新建 model 包,在包下新建一个实体类 User,User 信息如下:
public class User {
private String name;
private int age;
private String pass;
//setter、getter省略
}
在项目中新建 Web 包,并在 Web 包下新建一个类 WebController,在类中创建一个方法返回 User,如下:
@RestController
public class WebController {
@RequestMapping(name="/getUser", method= RequestMethod.POST)
public User getUser() {
User user=new User();
user.setName("小明");
user.setAge(12);
user.setPass("123456");
return user;
}
}
@RestController 注解相当于 @ResponseBody + @Controller 合在一起的作用,如果 Web 层的类上使用了 @RestController 注解,就代表这个类中所有的方法都会以 JSON 的形式返回结果,也相当于 JSON 的一种快捷使用方式;
@RequestMapping(name="/getUser", method= RequestMethod.POST),以 /getUser 的方式去请求,method= RequestMethod.POST 是指只可以使用 Post 的方式去请求,如果使用 Get 的方式去请求的话,则会报 405 不允许访问的错误。
不管是集合还是对象或者对象嵌套,Springboot都会把它转成json。
请求传参
请求传参是 Web 开发最基础的内容,前端浏览器和后端服务器正是依赖交互过程中的参数,来判断用户是否登录、用户正在执行时哪些动作,因此参数的传递和接收是一个 Web 系统最基础的功能。Spring Boot 内置了很多种参数接收方式,提供一些注解来帮助限制请求的类型、接收不同格式的参数等, 使用 Spring Boot 可以轻松的对请求做一些限制,比如为了安全我们只允许 POST 请求的访问,只需要在方法上添加一个配置既可:
@RequestMapping(name="/getUser", method= RequestMethod.POST)
public User getUser() {
...
}
这时如果请求为get类型就会报错。method= RequestMethod.GET为设置为get请求。如果不进行设置默认支持两种请求类型。
数据校验
输入验证是最重要的 Web 开发任务之一,在 Spring MVC 中有两种方式可以验证输入:一种是 Spring 自带的验证框架,另外一种是利用 JSR 实现。
JSR 是一个规范文档,指定了一整套 API,通过标注给对象属性添加约束。Hibernate Validator 就是 JSR 规范的具体实现,Hibernate Validator 提供了 JSR 规范中所有内置约束注解的实现,以及一些附加的约束注解,除此之外用户还可以自定义约束注解。
Spring Boot 的参数校验依赖于 hibernate-validator 来进行。使用 Hibernate Validator 校验数据,需要定义一个接收的数据模型,使用注解的形式描述字段校验的规则,举例如下:
首先在 WebController 添加一个保存的方法 saveUser,参数为 User。
@RequestMapping("/saveUser")
public void saveUser(@Valid User user,BindingResult result) {
System.out.println("user:"+user);
if(result.hasErrors()) {
List<ObjectError> list = result.getAllErrors();
for (ObjectError error : list) {
System.out.println(error.getCode()+ "-" + error.getDefaultMessage());
}
}
}
@Valid 参数前面添加 @Valid 注解,代表此对象使用了参数校验;
BindingResult 参数校验的结果会存储在此对象中,可以根据属性判断是否校验通过,校验不通过可以将错误信息打印出来。
接下来在 User 中给需要校验的参数添加对应的注解,对不同的属性,按照规则添加不同的校验内容。
public class User {
@NotEmpty(message="姓名不能为空")
private String name;
@Max(value = 100, message = "年龄不能大于100岁")
@Min(value= 18 ,message= "必须年满18岁!" )
private int age;
@NotEmpty(message="密码不能为空")
@Length(min=6,message="密码长度不能小于6位")
private String pass;
//...
}
自定义 Filter
Filter 也称之为过滤器,可以在前端拦截所有用户的请求,可以认为是 Servlet 的一种加强版,Web 开发人员通过 Filter 技术,对 Web 服务器管理的所有 Web 资源,例如 JSP、Servlet、静态图片文件或静态 HTML 文件等进行拦截,从而实现一些特殊的功能。例如,实现 URL 级别的权限访问控制、过滤敏感词汇、排除有 XSS 威胁的字符、记录请求日志等一些高级功能。
Spring Boot 内置了一些 Filter,比如,处理编码的 OrderedCharacterEncodingFilter 和请求转化的 HiddenHttpMethodFilter,也支持根据我们的需求来可以自定义 Filter。自定义 Filter 有两种实现方式,第一种是使用 @WebFilter,第二种是使用 FilterRegistrationBean,经过实践之后发现使用 @WebFilter 自定义的过滤器优先级顺序不能生效,因此推荐使用第二个方案。
自定义 Filter 两个步骤:
实现 Filter 接口,实现其中的 doFilter() 方法;
添加 @Configuration 注解,将自定义 Filter 加入过滤链。
新建 MyFilter 类,重写 doFilter() 方法:
public class MyFilter implements Filter {
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) srequest;
System.out.println("this is MyFilter,url :"+request.getRequestURI());
filterChain.doFilter(srequest, sresponse);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
将自定义 Filter 加入过滤链:
@Configuration
public class WebConfiguration {
@Bean
public FilterRegistrationBean testFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.setName("MyFilter");
registration.setOrder(6);
return registration;
}
}
当有多个过滤器时可以通过设置 Order 属性来决定它们的执行顺序,Order 值越小优先级越高。
配置文件
在 application.properties 中配置:
liudc.title=飘
liudc.description=我喜欢,我坚持
注:同时存在 application.yml 和 application.properties,并且里面配置相同,application.properties 的配置会覆盖 application.yml。
读取单个配置项
当需要从配置文件加载单个配置内容时,只需要使用 @Value 属性即可,新建 PropertiesTest 测试类进行测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class PropertiesTest {
@Value("${liudc.title}")
private String title;
@Test
public void testSingle() {
Assert.assertEquals(title," 飘");
}
}
@Value("${liudc.title}") 会默认读取 application.properties 或者 application.yml 文件中的 liudc.title 配置属性值,并赋值给 title。
Assert.assertEquals 是判断属性值是否和目标值一致。
读取多个配置
通常在项目中使用配置文件时,往往需要加载多个配置项,比如数据库连接参数等,通常会定义一个对象来接收多个配置项,方便在项目中使用。比如定义一个对象,来接收所有以 liudc 开头的配置内容。
@Component
@ConfigurationProperties(prefix="liudc")
public class LiudcProperties {
private String title;
private String description;
//省略getter settet方法
}
@Component 的定义为实例,方便在 Spring Boot 项目中引用;
@ConfigurationProperties(prefix="liudc"),表示以 liudc 开头的属性会自动赋值到对象的属性中,比如,liudc.title 会自动赋值到对象属性 title 中。
自定义配置文件
有时候需要自定义配置文件,以便和系统使用的 application.properties 文件区分开,避免混淆。Spring Boot 对这种情况也有很好的支持。此时需要多了一个注解来指明配置文件地址:@PropertySource("classpath:other.properties"),同样创建一个测试方法,检测是否正确加载了外部配置文件。