核心依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
请求处理
主要列举下几个核心注解
@Contrller
- 位置:类
- 作用:表示这个类是有一个控制器
- 说明:一般是需要搭配一个
@RequestMapping
注解,配置这个控制器的路径 - 注意:在没有
@ResponseBody
搭配的情况下,需要增加模板引擎依赖否则会报错
@ResponseBody
- 位置:类或方法
- 作用:告诉控制器,这个Action甚至整个Controller,返回的对象都将会序列化成JSON,并回传给HttpResponse
@RestController
- 位置:类
- 作用:快捷注解,相当于给类添加
@Contrller
+@ResponseBody
,2个注解
@RequestMapping
- 位置:类或方法
作用:几个参数及作用
value:指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
- method:指定请求的method类型, GET、POST、PUT、DELETE等;
- consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
- produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
- params:指定request中必须包含某些参数值是,才让该方法处理。
- headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
@GetMapping
- 位置:类或方法
- 作用:快捷注解,作用同
@RequestMapping
,只是限定了method=GET
@PostMapping
- 位置:类或方法
- 作用:快捷注解,作用同
@RequestMapping
,只是限定了method=POST
获取请求数据
获取常规请求参数
这里指的是Query String和Form中的参数
- Form参数只有在
POST
请求中才会获取 - 如果在
POST
请求中,Query String和Form,存在相同的参数,则最后会取Form的参数
例如:获取以下请求中的userName参数
/user/update/123?userName=zhangshan
代码示例:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/user")
public class TestController {
@PostMapping(value = "/update/{userId}")
public String update(@RequestParam String userName){
return userName;
}
}
获取url中的path变量
- 需要预先在
@RequestMapping
中定义 - 给参数加上@PathVariable
例如:获取以下请求url中的123
/user/update/123?userName=zhangshan
代码示例:
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/user")
public class TestController {
@PostMapping(value = "/update/{userId}")
public String update(
@RequestParam String userName,
@PathVariable String userId
){
return userId+"-"+userName;
}
}
将请求参数绑定到java对象上
TestBean.java
import lombok.Data;
@Data
public class TestBean {
private Integer userId;
private String userName;
}
TestController.java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/user")
public class TestController {
@PostMapping(value = "/update/{userId}")
public String update(
TestBean testBean
){
return testBean.getUserId()+"-"+testBean.getUserName();
}
}
经过测试,直接将请求参数绑定到java对象。优先级如下:
- url的query参数
- form的参数
- url的path参数
如果多处存在相同名称参数,优先级高的会覆盖优先级低的
获取json请求,并绑定到java对象
package com.example.demo;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/user")
public class TestController {
@PostMapping(value = "/update/{userId}")
public String update(
@RequestBody TestBean testBean
){
return testBean.getUserId()+"-"+testBean.getUserName();
}
}
@RequestBody
- 该注解,可以将客户端,发起post请求时,将request body中的json,直接映射成java对象
- json可以拿过来提交嵌套结构的对象,降低参数接收的复杂度
数据校验
@Valid 和 @Validated
@Valid
- 所在包:javax.validation.Valid
- 属于JSR-303规范
@Validated
- 所在包:org.springframework.validation.annotation.Validated
- @Validated是@Valid的一次封装,不是规范。
@Validated
相对于@Valid
,增加了分组校验- 在spirng开发中,我想应该更加推荐使用
基本验证规则
注解 | 可校验类型 | 说明 |
---|---|---|
@AssertFalse | Boolean,boolean | 验证注解的元素值是false |
@AssertTrue | Boolean,boolean | 验证注解的元素值是true |
@NotNull | 任意类型 | 验证注解的元素值不是null |
@Null | 任意类型 | 验证注解的元素值是null |
@Min(value=值) | BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存储的是数字)子类型 | 验证注解的元素值大于等于@Min指定的value值 |
@Max(value=值) | 和@Min要求一样 | 验证注解的元素值小于等于@Max指定的value值 |
@DecimalMin(value=值) | 和@Min要求一样 | 验证注解的元素值大于等于@ DecimalMin指定的value值 |
@DecimalMax(value=值) | 和@Min要求一样 | 验证注解的元素值小于等于@ DecimalMax指定的value值 |
@Digits(integer=整数位数, fraction=小数位数) | 和@Min要求一样 | 验证注解的元素值的整数位数和小数位数上限 |
@Size(min=下限, max=上限) | 字符串、Collection、Map、数组等 | 验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小 |
@Past | java.util.Date,java.util.Calendar;Joda Time类库的日期类型 | 验证注解的元素值(日期类型)比当前时间早 |
@Future | 与@Past要求一样 | 验证注解的元素值(日期类型)比当前时间晚 |
@NotBlank | CharSequence子类型 | 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的首位空格 |
@Length(min=下限, max=上限) | CharSequence子类型 | 验证注解的元素值长度在min和max区间内 |
@NotEmpty | CharSequence子类型、Collection、Map、数组 | 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) |
@Range(min=最小值, max=最大值) | BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子类型和包装类型 | 验证注解的元素值在最小值和最大值之间 |
@Email(regexp=正则表达式,flag=标志的模式) | CharSequence子类型(如String) | 验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式 |
@Pattern(regexp=正则表达式,flag=标志的模式) | String,任何CharSequence的子类型 | 验证注解的元素值与指定的正则表达式匹配 |
@Valid | 任何非原子类型 | 指定递归验证关联的对象;如用户对象中有个地址对象属性,如果想在验证用户对象时一起验证地址对象的话,在地址对象上加@Valid注解即可级联验证 |
校验示例
Book.java
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class Book {
@NotNull(message = "课本ID,不能为空")
private Integer bookId;
@NotBlank(message = "课本名称,不能为空")
private String bookName;
}
Stu.java
import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class Stu {
@NotNull(message = "学号,不能为空")
private Integer stuId;
@NotNull(message = "姓名,不能为空")
private String stuName;
@NotEmpty(message = "课本列表,不能为空")
@Valid //有嵌套对象的验证时,必须加上这个,不然会失效
private List<Book> bookList;
}
TestController.java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/user")
public class TestController {
@PostMapping(value = "/test")
public String test(@RequestBody @Validated Stu stu, BindingResult bindingResult) throws JsonProcessingException {
if (bindingResult.hasErrors()) {
return bindingResult.getFieldError().getDefaultMessage();
}
ObjectMapper mapper = new ObjectMapper();
return "提交成功" + mapper.writeValueAsString(stu);
}
}
302重定向
@GetMapping(value = "redirect")
public void redirect(HttpServletResponse response) throws IOException {
response.sendRedirect("http://www.baidu.com");
}
控制器之间跳转
@GetMapping(value = "redirect2")
public String redirect2() {
return "redirect:/otherController/otherAction?param1=1¶m2=1";
}
自定义错误路由
ErrorConfig.java
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@Configuration
public class ErrorConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST,"/400"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/500"));
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,"/404"));
container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED,"/401"));
};
}
}
ErrorCtrl.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RestController
public class ErrorCtrl {
@RequestMapping(value = "/500")
public String serverError(){
return "500";
}
@RequestMapping(value = "/400")
public String badRequest(){
return "400";
}
@RequestMapping(value = "/404")
public String notFound(){
return "404";
}
}
添加拦截器
第一步:首先需要添加一个拦截器类
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class UrlPrintInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURI());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
3个需要实现的方法,就不细说了,百度一大堆。请自行了解。
这里是一个很简单的拦截器,当请求进来的时候,把请求的uri打印出来。
第二部:添加一个WebMvc的配置类
import cn.cnvp.fw.saas.mch.web.interceptor.UrlInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Bean
public HandlerInterceptor getUrlInterceptor(){
return new UrlInterceptor();
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getUrlInterceptor())
.addPathPatterns("/**");
}
}
添加注册,并指定拦截的路径。大功告成。
jar包外静态资源的访问
import cn.cnvp.hx.saas.tmp1.Application;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.IOException;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//获取运行环境目录
@Bean
public static String getJarDir() {
ApplicationHome home = new ApplicationHome(Application.class);
System.out.println(home.getDir());
try {
return home.getDir().getCanonicalPath();
} catch (IOException e) {
return null;
}
}
//注意,一定要加上file:作为前缀。
//addResourceLocations还可以添加其他另外的资源定位方式
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println(getJarDir());
registry.addResourceHandler("/**").addResourceLocations("file:"+getJarDir()+"/");
registry.addResourceHandler("/uploads/**").addResourceLocations("file:"+getJarDir()+"/upload");
}
}