本篇介绍 SpringBoot 对 Web 开发的支持。
从上篇文章可知,SpringBoot 对 Web 开发做了很大的优化,包括开发、测试、部署都做了支持。本篇内容介绍 SpirngBoot 对 Web 提供的其他便利。
kspring-boot-starter-web 是 SpringBoot 对 Web 开发的支持,主要包括 Restful、参数校验、使用 Tomcat 作为内嵌容器等功能,接下来一一介绍。
Web开发
SpringBoot Web开发非常的简单,其中包括常用的json输出、filters、property、log等
json 接口开发
在 SpringBoot 体系中,天然对 Json 支持,在上篇文章中给大家做了简单的演示,这次来深入使用一番。
新建一个项目 spring-boot-web,添加上篇同样的组件依赖,导入项目到 Idea 中。在项目路径下新建 domain 包,在包下新建一个实体类 User,User 信息如下:
package com.example.webdemo.domain;
public class User {
private String name;
private int age;
private String pass;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
}
在项目中新建 web 包,并在 web 包下新建一个类 WebController,在类中创建一个方法返回 User,如下:
package com.example.webdemo.web;
import com.example.domain.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class WebController {
@RequestMapping("/getUser")
public User getUser(){
User user = new User();
user.setName("欧阳德华");
user.setAge(26);
user.setPass("123456");
return user;
}
}
在 Test 包下新建 WebControllerTest 测试类,对 getUser() 方法进行测试。
package com.example.webdemo;
import com.example.web.WebController;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
@SpringBootTest
public class WebControllerTest {
private MockMvc mockMvc;
@Before
public void setUp() throws Exception{
mockMvc = MockMvcBuilders.standaloneSetup(new WebController()).build();
}
@Test
public void getUser()throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/getUser")).andDo(print());
}
}
返回结果如下:
说明 Spring Boot 自动将 User 对象转成了 Json 进行返回。那么如果返回的是一个 list 呢,在 WebController 添加方法 getUsers():
@RequestMapping("/getUsers")
public List<User> getUsers(){
List<User> users = new ArrayList<User>();
User user1 = new User();
user1.setName("蔡文姬");
user1.setAge(8);
user1.setPass("111111");
users.add(user1);
User user2 = new User();
user2.setName("甄姬");
user2.setAge(22);
user2.setPass("222222");
users.add(user2);
return users;
}
在WebControllerTest添加相关测试方法如下:
@Test
public void getUsrs()throws Exception{
mockMvc.perform(MockMvcRequestBuilders.post("/getUsers")).andDo(print());
}
返回内容如下:
说明不管是对象还是集合或者对象嵌套,Spring Boot 均可以将其转化为 Json 字符串,特别适合我们给其他系统提供接口时使用。
请求传参
使用 Spirng Boot 可以轻松的对请求做一些限制,比如为了安全只允许 POST 请求的访问。只需要在方法上添加一个配置即可:
@RequestMapping(value = "/getUser", method = RequestMethod.POST)
public User getUser(){
User user = new User();
user.setName("欧阳德华");
user.setAge(26);
user.setPass("123456");
return user;
}
这时候再以 get 请求去访问,就会返回: Request method 'GET' not supported。
Spring Web 层支持多种方法传参,上篇文章中传入一个属性 name,其直接使用对象接收也是支持的。
@RequestMapping(name="/getUser", method= RequestMethod.POST)
public String getUser(User user) {
...
}
这样的写法,只要是 User 的属性都会被自动填充到 user 对象中。还有另外一种传参的方式。
使用 Url 进行传参,这种形式的传参地址栏会更加美观一些。
@RequestMapping(value = "/getUserByName/{name}", method = RequestMethod.GET)
public User getUserByName(@PathVariable String name){
User user = new User();
user.setName(name);
user.setAge(20);
user.setPass("636281");
return user;
}
浏览器访问:http://localhost:8080/getUserByName/Jacky,返回
参数校验
参数校验在我们日常开发中非常常见,最基本的校验有判断属性是否为空、长度是否符合要求等,在传统的开发模式中需要写一堆的 if else 来处理这些逻辑,很繁琐,效率也低。使用 @Valid + BindingResult 就可以优雅地解决这些问题,接下来看看示例:
首先在 WebController 添加一个保存用户的方法 saveUser,参数为 User,现在需要对参数 User 做校验:
@NotEmpty(message="姓名不能为空!")
private String name;
@Max(value = 100,message = "年龄小于38岁!")
@Min(value = 16,message = "必须大于16岁!")
private int age;
@NotEmpty(message = "密码不能为空!")
@Length(min = 6,message = "密码长度不能小于6位!")
private String pass;
对不同的属性,按照规则添加了不同校验内容。
Spring Boot 的参数校验其实是依赖于 hibernate-validator 来进行。现在模拟对参数 User 进行参数校验,使用 @Valid + BindingResult,校验后如果有错误将错误打印出来,代码如下:
@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());
}
}
}
}
添加测试方法进行测试:
@Test
public void saveUser() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.post("/saveUser")
.param("name","")
.param("age","12")
.param("pass","test")
).andDo(print());
}
结果返回:
定义 Filter
我们常常在项目中会使用 Filters 用于记录请求日志、排除有 XSS 威胁的字符、执行权限验证等等。Spring Boot 自动添加了 OrderedCharacterEncodingFilter 和 HiddenHttpMethodFilter,并且可以自定义 Filter。
自定义 Filter 两个步骤:
实现 Filter 接口,实现 Filter 方法 添加@Configuration 注解,将自定义 Filter 加入过滤链
新建 MyFilter 类,使用 doFilter() 方法:
@WebFilter(filterName = "MyFilter")
public class MyFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
System.out.println("正在使用自定义过滤器,您访问的地址是:" + request.getRequestURI());
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
将自定义 Filter 加入过滤链:
@Configuration
public class WebConfiguration {
@Bean
public RemoteIpFilter remoteIpFilter(){
return new RemoteIpFilter();
}
@Bean
public FilterRegistrationBean testFilterRegistation(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter("paramName","paramValue");
registrationBean.setName("MyFilter");
registrationBean.setOrder(1);
return registrationBean;
}
}
添加完后启动项目,访问任意的 Url,都会看到控制台打印如下信息:
说明 MyFilter 已经对所有的 Url 进行了监控,在实际使用的过程中,常常利用这个特性进行 session 验证,判断用户是否登录。
自定义 Property
在 Web 开发的过程中,经常需要自定义一些配置文件,如何使用呢?
配置在 application.properties 中
com.zat.mpaytitle="范总工"
com.zat.gametitle="渣渣辉"
自定义配置类:
@Component
public class ZatProperties {
@Value("${com.zat.mpaytitle}")
private String mpayTitle;
@Value("${com.zat.gametitle}")
private String gameTitle;
public String getMpayTitle() {
return mpayTitle;
}
public void setMpayTitle(String mpayTitle) {
this.mpayTitle = mpayTitle;
}
public String getGameTitle() {
return gameTitle;
}
public void setGameTitle(String gameTitle) {
this.gameTitle = gameTitle;
}
}
写单元测试进行验证:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PropertiesTest {
@Resource
private ZatProperties zatProperties;
@Test
public void TestProperies()throws Exception{
System.out.println("Mpay的Title是:" + zatProperties.getMpayTitle());
System.out.println("Game的Title是:" + zatProperties.getGameTitle());
}
}
运行 PropertiesTest 后输出结果:
如果测试中出现中文乱码,可安装以下方法进行设置:
注意:.propertity里的属性文件名称只能全部用小写英文+"."号分隔,绝对不能用大写英文!
配置完成后一定要重新新建一个application.properties