threadLocal = new ThreadLocal<>();
13 |
14 | public static void setCurrentId(Long id) {
15 | threadLocal.set(id);
16 | }
17 |
18 | public static long getCurrentId() {
19 | return threadLocal.get();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/common/CustomException.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.common;
2 |
3 | /**
4 | * Project: rikky-takeaway - CustomException 自定义异常类
5 | *
Powered by river On 2023/01/08 8:52 PM
6 | *
7 | * @author Riverify
8 | * @version 1.0
9 | * @since JDK8
10 | */
11 | public class CustomException extends RuntimeException {
12 | /**
13 | * 这个异常将会被{@link GlobalExceptionHandler}捕获,然后返回给前端。
14 | *
15 | * @param message 异常信息
16 | */
17 | public CustomException(String message) {
18 | super(message);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/common/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.common;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.stereotype.Controller;
5 | import org.springframework.web.bind.annotation.ControllerAdvice;
6 | import org.springframework.web.bind.annotation.ExceptionHandler;
7 | import org.springframework.web.bind.annotation.ResponseBody;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | import java.sql.SQLIntegrityConstraintViolationException;
11 |
12 | /**
13 | *
Project: rikky-takeaway - GlobalExceptionHandler 全局异常处理
14 | *
Powered by Riverify On 12-17-2022 23:21:42
15 | *
16 | *
通过 @ControllerAdvice注解声明一个控制器建言,对有 @RestController和 @Controller注解的控制器的方法加一些公共的操作
17 | *
通过 @ResponseBody注解将返回的数据转换成 JSON 格式
18 | *
通过 @Slf4j注解声明一个日志对象
19 | *
20 | * @author Riverify
21 | * @version 1.0
22 | * @since JDK8
23 | */
24 |
25 | @ControllerAdvice(annotations = {RestController.class, Controller.class})
26 | @ResponseBody
27 | @Slf4j
28 | public class GlobalExceptionHandler {
29 |
30 | /**
31 | * 处理异常{@link SQLIntegrityConstraintViolationException},本项目中主要处理注册时输入重复数据的异常
32 | *
SQL报错的错误信息进行切片处理,返回特定的错误信息,即某个账号已存在。
33 | *
通过 @ExceptionHandler注解声明该方法是一个异常处理方法,可以处理的异常类型为 {@link SQLIntegrityConstraintViolationException}。
34 | *
35 | * @param exception 异常,example:com.mysql.cj.jdbc.exceptions.SQLIntegrityConstraintViolationException: Duplicate entry 'riverify' for key 'username'
36 | * @return 返回一个通用的结果对象
37 | */
38 | @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
39 | public R exceptionHandler(SQLIntegrityConstraintViolationException exception) {
40 | log.error("SQLIntegrityConstraintViolationException异常: {}", exception.getMessage());
41 | // 当异常信息中包含“Duplicate entry”时,说明是主键冲突异常,返回数据重复的错误信息
42 | if (exception.getMessage().contains("Duplicate entry")) {
43 | // 提取出错误的具体情况,并返回给前端
44 | String[] split = exception.getMessage().split("'"); // Duplicate entry 'riverify' for key 'employee.idx_username' 以单引号切片
45 | return R.error(split[1] + " 已存在"); // 返回数据重复的账号, 如 riverify已存在
46 | }
47 | // 其他异常,返回未知错误
48 | return R.error("操作失败,未知错误");
49 | }
50 |
51 | /**
52 | * 处理自定义异常{@link CustomException},通过在程序中使用如:throw new CustomException("xxx")抛出异常后,在这里被捕获并返回给前端(使用R对象包装)
53 | * 通过 @ExceptionHandler注解声明该方法是一个异常处理方法,可以处理的异常类型为 {@link CustomException}。
54 | *
55 | * @param exception 自定义异常
56 | * @return 返回一个通用的结果对象,用于前端错误内容的展示
57 | */
58 | @ExceptionHandler(CustomException.class)
59 | public R exceptionHandler(CustomException exception) {
60 | log.error("发生自定义异常: {}", exception.getMessage());
61 | // 其他异常,返回未知错误
62 | return R.error(exception.getMessage());
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/common/JacksonObjectMapper.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.common;
2 |
3 | import com.fasterxml.jackson.databind.DeserializationFeature;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.fasterxml.jackson.databind.module.SimpleModule;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
8 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
9 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
10 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
11 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
12 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
13 |
14 | import java.math.BigInteger;
15 | import java.time.LocalDate;
16 | import java.time.LocalDateTime;
17 | import java.time.LocalTime;
18 | import java.time.format.DateTimeFormatter;
19 |
20 | import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
21 |
22 | /**
23 | * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
24 | * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
25 | * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
26 | */
27 | public class JacksonObjectMapper extends ObjectMapper {
28 |
29 | public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
30 | public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
31 | public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
32 |
33 | public JacksonObjectMapper() {
34 | super();
35 | //收到未知属性时不报异常
36 | this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
37 |
38 | //反序列化时,属性不存在的兼容处理
39 | this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
40 |
41 |
42 | SimpleModule simpleModule = new SimpleModule()
43 | .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
44 | .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
45 | .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
46 |
47 | .addSerializer(BigInteger.class, ToStringSerializer.instance)
48 | .addSerializer(Long.class, ToStringSerializer.instance) // Long类型转String,避免js精度丢失
49 | .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
50 | .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
51 | .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
52 |
53 | //注册功能模块 例如,可以添加自定义序列化器和反序列化器
54 | this.registerModule(simpleModule);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/common/MyMetaObjectHandler.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.common;
2 |
3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.ibatis.reflection.MetaObject;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.time.LocalDateTime;
9 |
10 | /**
11 | * Project: rikky-takeaway - MetaObjectHandler 数据库相应字段的自动填充,自定义元数据对象处理器
12 | *
Powered by Riverify On 12-27-2022 20:05:51
13 | *
14 | * @author Riverify
15 | * @version 1.0
16 | * @since JDK8
17 | */
18 | @Slf4j
19 | @Component
20 | public class MyMetaObjectHandler implements MetaObjectHandler {
21 |
22 | /**
23 | * 插入时自动填充
24 | *
25 | * @param metaObject
26 | */
27 | @Override
28 | public void insertFill(MetaObject metaObject) {
29 | log.info("公共字段自动填充[insert]...");
30 | log.info(metaObject.toString());
31 | metaObject.setValue("createTime", LocalDateTime.now());
32 | metaObject.setValue("updateTime", LocalDateTime.now());
33 | metaObject.setValue("createUser", BaseContext.getCurrentId()); // 从 ThreadLocal 中获取当前用户的 id
34 | metaObject.setValue("updateUser", BaseContext.getCurrentId()); // 从 ThreadLocal 中获取当前用户的 id
35 | }
36 |
37 |
38 | /**
39 | * 更新时自动填充
40 | *
41 | * @param metaObject
42 | */
43 | @Override
44 | public void updateFill(MetaObject metaObject) {
45 | log.info("公共字段自动填充[update]...");
46 | log.info(metaObject.toString());
47 |
48 | long id = Thread.currentThread().getId(); // 获取当前线程的id
49 | log.info("当前线程id={}", id); // Slf4j的日志输出
50 |
51 | metaObject.setValue("updateTime", LocalDateTime.now());
52 | metaObject.setValue("updateUser", BaseContext.getCurrentId()); // 从ThreadLocal中获取当前线程的用户id
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/common/R.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.common;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 |
9 | /**
10 | * 通用返回结果类
11 | *
服务端相应的数据最终都会封装成此对象
12 | *
13 | * @param
14 | */
15 | @Data
16 | public class R {
17 |
18 | /**
19 | * 编码:1成功,0和其它数字为失败
20 | */
21 | private Integer code;
22 |
23 | /**
24 | * 错误信息
25 | */
26 | private String msg;
27 |
28 | /**
29 | * 具体数据
30 | */
31 | private T data;
32 |
33 | /**
34 | * 动态数据
35 | */
36 | private Map map = new HashMap();
37 |
38 |
39 | /**
40 | * 成功即返回数据和成功代码
41 | *
42 | * @param object 成功的信息对象
43 | * @param
44 | * @return 返回该类的泛型的结果R对象,包含有成功代码和数据
45 | */
46 | public static R success(T object) {
47 | R r = new R();
48 | r.data = object;
49 | r.code = 1;
50 | return r;
51 | }
52 |
53 | /**
54 | * 失败
55 | *
56 | * @param msg 错误信息
57 | * @param
58 | * @return 返回该类的泛型的结果R对象,包含有失败代码和错误信息
59 | */
60 | public static R error(String msg) {
61 | R r = new R();
62 | r.msg = msg;
63 | r.code = 0;
64 | return r;
65 | }
66 |
67 | public R add(String key, Object value) {
68 | this.map.put(key, value);
69 | return this;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.config;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
4 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | /**
9 | * Project: rikky-takeaway - MybatisPlusConfig 配置MP分页插件
10 | *
Powered by Riverify On 12-20-2022 16:25:03
11 | *
12 | * @author Riverify
13 | * @version 1.0
14 | * @since JDK8
15 | */
16 | @Configuration
17 | public class MybatisPlusConfig {
18 |
19 | @Bean
20 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
21 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
22 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // PaginationInnerInterceptor MP提供的分页插件
23 | return interceptor;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/fubukiss/rikky/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.fubukiss.rikky.config;
2 |
3 | import org.springframework.cache.annotation.CachingConfigurerSupport;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.data.redis.connection.RedisConnectionFactory;
7 | import org.springframework.data.redis.core.RedisTemplate;
8 | import org.springframework.data.redis.serializer.StringRedisSerializer;
9 |
10 | /**
11 | *
Project: rikky-takeaway - RedisConfig
12 | *
Powered by river On 2023/02/04 9:12 PM
13 | *
14 | * @author Riverify
15 | * @version 1.0
16 | * @since JDK8
17 | */
18 | @Configuration
19 | public class RedisConfig extends CachingConfigurerSupport {
20 |
21 | @Bean
22 | public RedisTemplate