一.yml
配置文件语法
1.配置自定义数据
1.1 配置普通数据
语法:key: value
name: kaifamiao
1.2配置对象数据
语法1:
key:
key1: value1;
key2: value2;
person:
name: zhangsan
age: 19
语法2:
key: {key1: value1,key: value2}
person1: {name: lisi,age: 21}
1.3配置Map
数据
同配置对象数据
1.4配置数组(list,set)数据
语法1:
key:
— value1
— value2
student:
- maqi
- sunliu
语法2:
key: [value1,value2]
student1: [phr,lzh,zk]
集合中的元素可以是对象
student2:
- name: zhangkui
age: 22
gender: 男
- name: penghaorun
age: 21
gender: 男
二.配置问件与配置类的映射关系
1.使用注解@Value
例如yml
问件如下:
name: kaifamiao
person:
name: zhangsan
age: 19
获取数据的代码则如下:
package com.lzh.mybatis_springboot.testyml;
import com.lzh.mybatis_springboot.model.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class Yml {
//获取单个属性
@Value("${name}")
private String name;
//获取对象属性
@Value("${person.name}")
private String getName;
@Value("${person.age}")
private Integer age;
@Test
public void test() {
System.out.println(name);
System.out.println(getName);
System.out.println(age);
}
}
2.使用Environment
类
yml文件如下:
person:
name: zhangsan
age: 19
获取数据:
package com.lzh.mybatis_springboot.controller;
import com.lzh.mybatis_springboot.model.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestYmlController {
//直接注入 Environment对象environment 使用environment.getProperty()方法取值
@Autowired
Environment environment;
@Autowired
Person person;
@RequestMapping("/test")
public String test(){
System.out.println(environment.getProperty("name"));
System.out.println(environment.getProperty("person.name"));
System.out.println(environment.getProperty("student[0]"));
System.out.println(person);
return "/emp/list";
}
}
3.使用@ConfigurationProperties(prefix = "配置文件中的key的前缀")
注解
yml
文件
person:
name: zhangsan
age: 19
实体类
package com.lzh.mybatis_springboot.model;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data//为什么要写这个注解,是因为使用注解@ConfigurationProperties在获取数据的时候需要set方法
//person是指配置文件中的key的前缀
@ConfigurationProperties(prefix = "person")
@Component
public class Person {
private String name;
private int age;
}
获取数据
package com.lzh.mybatis_springboot.testyml;
import com.lzh.mybatis_springboot.model.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.awt.print.Pageable;
@SpringBootTest
public class ConfigYml {
@Autowired
Person person;
@Test
public void test() {
System.out.println(person.getAge());
}
}
注意:使用@ConfigurationProperties
方式可以进行配置文件与实体字段的自动映射,但需要字段
必须提供set
方法才可以,而使用@Value
注解修饰的字段不需要提供set
方法
三.拦截器
拦截器不会拦截静态资源,Spring Boot
的默认静态目录为 resources/static
,该目录下的静态页面、
JS
、CSS
、图片等不会被拦截,当然这也要看实现过程,有些情况下可能会被拦截.
1.拦截器使用步骤:
1.1定义拦截器
创建一个类实现HandlerInterceptor
接口,重写三个方法
preHandle(……) 方法
该方法的执行时机是,当某个 URL 已经匹配到对应的 Controller
中的某个方法,且在这个方法执行之
前。所以 preHandle(……)
方法可以决定是否将请求放行,这是通过返回值来决定的,返回 true
则放
行,返回 false
则不会向后执行。
postHandle(……) 方法
该方法的执行时机是,当某个 URL 已经匹配到对应的 Controller 中的某个方法,且在执行完了该方法,
但是在 DispatcherServlet
视图渲染之前。所以在这个方法中有个 ModelAndView
参数,可以在此做一
些修改动作。
afterCompletion(……) 方法
顾名思义,该方法是在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,这个
方法只有在 preHandle(……)
被成功执行后并且返回 true
才会被执行。
package com.lzh.mybatis_springboot.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 实现HandlerInterceptor接口 重写方法
* 实现未登录用户不可以访问登录页面之外的其他页面
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();//获取Session,因为用户的登录信息时存在session里面的
Object user = session.getAttribute("loginUser");//使用该方法获取存在session域中的值
if(user==null){//如果为空,证明session中没有该用户,重定向到登录页面
response.sendRedirect(request.getContextPath()+"/user/login");
return false;
}
System.out.println("用户登录了,放行");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("执行完方法之后进执行(Controller方法调用之后),但是此时还没进行视图渲
染");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception{
log.info("整个请求都处理完咯,DispatcherServlet也渲染了对应的视图咯,此时我可
以做一些清理的工作了");
}
}
1.2配置拦截器
实现 WebMvcConfigurer
接口,重写addInterceptors()
方法
package com.lzh.mybatis_springboot.config;
import com.lzh.mybatis_springboot.interceptor.AccessIPInterceptor;
import com.lzh.mybatis_springboot.interceptor.LoginCountInterceptor;
import com.lzh.mybatis_springboot.interceptor.MyInterceptor;
import com.lzh.mybatis_springboot.interceptor.RequestManyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置拦截器
*/
@Component
public class MyConfig implements WebMvcConfigurer {
@Autowired
MyInterceptor myInterceptor;
@Autowired
AccessIPInterceptor accessIPInterceptor;
@Autowired
LoginCountInterceptor loginCountInterceptor;
@Autowired
RequestManyInterceptor requestManyInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// InterceptorRegistration interceptor = registry.addInterceptor(myInterceptor);//配置拦截器对象
// InterceptorRegistration pathPatterns = interceptor.addPathPatterns("/*");
// //哪些资源可以进入拦截器
// InterceptorRegistration excluded = interceptor.excludePathPatterns("/css");
// //哪些资源不进入拦截器
// registry.addInterceptor(myInterceptor).addPathPatterns("/**").
// excludePathPatterns("/login", "/captcha", "/js/**", "/css/**", "/font/**");
registry.addInterceptor(loginCountInterceptor).addPathPatterns("/login")
.excludePathPatterns("/logins", "/captcha", "/js/**", "/css/**", "/font/**", "/block/blocked");
registry.addInterceptor(requestManyInterceptor).addPathPatterns("/**")
.excludePathPatterns("/login", "/captcha", "/js/**", "/css/**", "/font/**", "/block/blocked");
registry.addInterceptor(accessIPInterceptor).addPathPatterns("/**")
.excludePathPatterns("/login", "/captcha", "/js/**", "/css/**", "/font/**", "/block/blocked");
}
}
四.请求参数校验及其异常处理
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
1.三种校验方式
- 业务层校验
-
Validator
+BindResult
校验 -
Validator
+ 自动抛出异常
2.Validator
+ 自动抛出异常(使用)
2.1在实体类字段上加上对应的注解
@Data
public class User implements Serializable {
@NotNull(message = "用户id不能为空")
private Long id;
@NotNull(message = "用户账号不能为空")
@Size(min = 6, max = 11, message = "账号长度必须是6-11个字符")
private String account;
@NotNull(message = "用户密码不能为空")
@Size(min = 6, max = 11, message = "密码长度必须是6-16个字符")
private String password;
@NotNull(message = "用户邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
}
2.2异常处理
在controller层传入的时候,加上注解@Validated ,并传入BindingResult bindingResult
,用bindingResult.getAllErrors();
获取错误信息集合
@RestController
public class UserController {
@RequestMapping("/insert")
public String insert(@RequestBody @Validated User user BindingResult bindingResult ) {
List<ObjectError> allErrors = bindingResult.getAllErrors();
if (allErrors != null) {
StringBuilder message = new StringBuilder();
for (ObjectError oe : allErrors) {
String msg = oe.getDefaultMessage();
message.append(msg).append(",");
}
return message.substring(0, message.length() - 1);
}
return "success";
}
}
(去掉BindingResult
后会自动引发异常,异常发生了自然而然就不会执行业务逻辑
3.全局异常处理
如果不想在controller层手动获取异常,使用全局异常处理
步骤:
- 写一个类,类上加上注解
@RestControllerAdvice
- 类中写一个方法,方法上加上注解
@ExceptionHandler这里写异常的的字节码对象)
/**
* 全局异常处理
* 使用form-data方式调用接口,校验异常抛出 BindException
* 使用 json 请求体调用接口,校验异常抛出 MethodArgumentNotValidException
* 单个参数校验异常抛出ConstraintViolationException
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理 json 请求体调用接口校验失败抛出的异常
*
* @param ex 程序执行发生的异常
* @return 响应实体对象
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultVO<String>
handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
List<FieldError> fieldErrors =
ex.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream().map(o ->
o.getDefaultMessage()).collect(Collectors.toList());
return ResultVO.failure(ResponseCode.VALIDATE_ERROR_CODE, "参数校验错
误", collect.toString());
}
/**
* 处理使用 form-data 方式调用接口,校验异常抛出 BindException
*
* @param ex 程序执行发生的异常
* @return 响应实体对象
*/
@ExceptionHandler(BindException.class)
public ResultVO<String> handleBindException(BindException ex) {
List<FieldError> fieldErrors =
ex.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream().map(o ->
o.getDefaultMessage()).collect(Collectors.toList());
return ResultVO.failure(ResponseCode.VALIDATE_ERROR_CODE, "参数校验错
误", collect.toString());
}
}