记录了一些SpringBoot项目实战过程中知识点和常用思路
项目实战
全局异常捕获
- 创建全局异常类
- 通过@RestControllerAdvice注解将该类作用于全部controller类
- 在该类创建方法编写异常处理逻辑,行参为需要捕获的异常类
- 通过@ExceptionHandler注解捕获异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.sky.handler;
import com.sky.constant.MessageConstant; import com.sky.exception.BaseException; import com.sky.result.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler {
@ExceptionHandler public Result exceptionHandler(BaseException ex){ log.error("异常信息:{}", ex.getMessage()); return Result.error(ex.getMessage()); }
@ExceptionHandler public Result doSQLException(SQLIntegrityConstraintViolationException ex){ log.error("异常信息, {}", ex.getMessage()); String message = ex.getMessage(); if (message.contains("Duplicate")){ return Result.error(message.split(" ")[2] + MessageConstant.ALREADY_EXIST); } return Result.error(MessageConstant.UNKNOWN_ERROR); }
}
|
@RestControllerAdvice |
所有被@RestController注解的类/方法执行时都会触发该类 |
@ExceptionHandler |
被注解方法能够捕获异常 |
@InitBinder |
用来设置WebDataBinder,用于自动绑定前台请求参数到Model中(当表单数据需要转化时使用) |
@ModelAttribute |
本来作用是绑定键值对到Model中,当与@RestControllerAdvice配合使用时,可以让全局的@RequestMapping都能获得在此处设置的键值对。 |
ThreadLocal
ThreadLocal可以创建一个同一线程共享空间,一次请求在不同的层次为统一线程,所以该空间可以在拦截器,controller,service,mapper个层级之间共享。
public void set(T value) |
设置当线程的线程局部变量的值 |
public T get() |
返回当前线程所对应的线程局部变量的值 |
public void remove() |
移除当前线程的线程局部变量 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.sky.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) { threadLocal.set(id); }
public static Long getCurrentId() { return threadLocal.get(); }
public static void removeCurrentId() { threadLocal.remove(); }
}
|
PageHelper 分页插件
1 2 3 4 5 6 7 8
| public PageResult page(EmployeePageQueryDTO dto) { PageHelper.startPage(dto.getPage(),dto.getPageSize());
Page<Employee> page = employeeMapper.list(dto.getName()); return new PageResult(page.getTotal(), page.getResult()); }
|
日期格式化问题
由于配置类WebMvcConfigurationSupport存在序列化问题,当配置类继承该类时会导致日期格式以数组形式返回
解决方法:
1. 在属性上加入注解
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Employee { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime;
private Long createUser;
private Long updateUser;
}
|
- 在配置类中扩展Spring
MVC的消息转换器,统一对日期类型进行格式化处理(推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { log.info("扩展消息转换器"); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setObjectMapper(new JacksonObjectMapper()); converters.add(0, converter); }
package com.sky.json;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm"; public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() { super(); this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule() .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))) .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
this.registerModule(simpleModule); } }
|
实体类拷贝
1 2 3 4 5 6 7 8 9
| @Override public void update(EmployeeDTO employeedto) { Employee employee1 = new Employee(); BeanUtils.copyProperties(employeedto, employee1); employee1.setUpdateTime(LocalDateTime.now()); employee1.setUpdateUser(BaseContext.getCurrentId()); employeeMapper.update(employee1); }
|
公共字段填充