1️⃣
 

Validated自定义AOP

java

/** * 请求参数校验切面,统一对Controller中@RequestBody映射的对象进行校验,在Controller方法中无需单独处理 */ @Aspect @Slf4j @EnableAspectJAutoProxy @Component public class ValidatedAspect { @Resource private Validator validator; @Around("execution(* com.sl..controller.*Controller.*(..))") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 获取@RequestBody映射的对象 Object body = AspectUtil.getBody(proceedingJoinPoint); // 不为空的body进行拦截校验 if (!ObjectUtil.isEmpty(body)) { // 进行校验 Set<ConstraintViolation<Object>> validateResult = validator.validate(body); if (CollUtil.isNotEmpty(validateResult)) { //没有通过校验,抛出异常,由统一异常处理机制进行处理,响应400 String info = JSONUtil.toJsonStr(validateResult.stream() .map(ConstraintViolation::getMessage).collect(Collectors.toList())); throw new SLException(info, HttpStatus.BAD_REQUEST.value()); } } //校验通过,执行原方法 return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); } }
Java

java

/** * 获取请求体 * * @param pjp {@link ProceedingJoinPoint} * @return {@code Object} */ public static Object getBody(ProceedingJoinPoint pjp) { Object[] args = pjp.getArgs(); Method method = getMethod(pjp); if (ObjectUtil.isNotEmpty(args)) { Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int count = 0; count < parameterAnnotations.length; count++) { for (Annotation annotation : parameterAnnotations[count]) { if (annotation instanceof RequestBody) { return args[count]; } } } } return null; }
Java

两种异常 Advice全局异常处理

@RestControllerAdvice @ExceptionHandler(ValidationException.class)

@Resource @Autowired

Java标准vs Spring标准
notion image
Nacos配置共享与覆盖
单机日志logback.xml
 
通过加入一个@Builder

java

package com.sl.ms.carriage.domain.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Data; import javax.validation.constraints.*; import java.time.LocalDateTime; import java.util.List; /** * 运费模板对象 */ @Data @Builder public class CarriageDTO { /** * 运费模板id */ @ApiModelProperty(value = "运费模板id") private Long id; /** * 模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省 */ @ApiModelProperty(value = "模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省", required = true) @Max(value = 4, message = "类型值必须是1、2、3、4") @Min(value = 1, message = "类型值必须是1、2、3、4") @NotNull(message = "模板类型不能为空") private Integer templateType; /** * 运送类型:1-普快,2-特快 */ @ApiModelProperty(value = "运送类型:1-普快,2-特快", required = true) @Max(value = 2, message = "类型值必须是1、2") @Min(value = 1, message = "类型值必须是1、2") @NotNull(message = "运送类型不能为空") private Integer transportType; /** * 关联城市:1-全国,2-京津冀,3-江浙沪,4-川渝,5-黑吉辽 */ @ApiModelProperty(value = "关联城市:1-全国,2-京津冀,3-江浙沪,4-川渝,5-黑吉辽", required = true) @NotNull(message = "关联城市不能为空") private List<String> associatedCityList; /** * 首重价格 */ @ApiModelProperty(value = "首重价格", required = true) @DecimalMin(value = "1.0", message = "首重价格必须大于等于1") @DecimalMax(value = "999.9", message = "首重价格必须小于等于999.9") @NotNull(message = "首重价格不能为空") private Double firstWeight; /** * 续重价格 */ @ApiModelProperty(value = "续重价格", required = true) @DecimalMin(value = "1.0", message = "续重价格必须大于等于1") @DecimalMax(value = "999.9", message = "续重价格必须小于等于999.9") @NotNull(message = "续重价格不能为空") private Double continuousWeight; /** * 轻抛系数 */ @ApiModelProperty(value = "轻抛系数", required = true) @Min(value = 1, message = "轻抛系数必须大于等于1") @Max(value = 99999, message = "轻抛系数必须小于等于99999") @NotNull(message = "轻抛系数不能为空") private Integer lightThrowingCoefficient; /** * 创建时间 */ @ApiModelProperty(value = "创建时间") private LocalDateTime created; /** * 更新时间 */ @ApiModelProperty(value = "更新时间") private LocalDateTime updated; @ApiModelProperty(value = "运费") private Double expense; @ApiModelProperty(value = "计费重量,单位:kg") private Double computeWeight; }
Java
会出现以下错误

java

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.sl.ms.carriage.domain.dto.CarriageDTO]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.sl.ms.carriage.domain.dto.CarriageDTO` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:388) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:343) at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:185) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:160) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:133) at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122) at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.sl.ms.carriage.domain.dto.CarriageDTO` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2] at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1904) at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1349) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1415) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:351) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:184) at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3682) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:380) ... 51 common frames omitted
Java
数值没用枚举 在范围内其他暂无意义的值可以随便插入()
实际上并没有多个
notion image
(多条记录实现 但共用一套模版时?)
新增或更新运费模板业务修改
业务思路补充解释:
假设传过来id为1类型为B的记录:
有id→修改行为 查询id≠1的所有B类型记录 没有插入
有则判断 如果是非经济区 即为重复
场景为:id为1类型为A的记录 希望修改为B类型 但B类型已存在 拒绝修改
 
存在问题:如果是经济区更新操作,数据库已有的关联城市为2,本次修改为2,3,修改就是不可能(经济区可以接受多个关联城市)。
如果传入2,3 则因为交集 被拒绝修改
如果传入3 会按照覆盖更新处理,会2 → 3
应该每次传入DTO后排序关联城市List,最后join成字符串保存,这样交集的逻辑就改为字符串相等判断,此场景下传入2,3更新直接覆盖2
 
notion image
 
根据体积参数与实际重量计算计费重量业务
规则引擎
职责链模式
缓存 id 大key数据
缓存重复(A→B B→A)需要对组合进行排序
若加入自定义 不可用 同时查询两个

Day02练习参考

删除

 

缓存与自定义模版

 
 
 
 
 
并发计算压力
带宽占用
服务端hutool base64 → 客户端生成
 
 
UT测试结果
Redis数据结果
更新后删
notion image
notion image
notion image
 

职责链模式确定模板

引入依赖与配置
notion image

设计思路

1.上下文:除开同城模版,其他模板的处理链都需要使用寄与收的省份Id,要避免链上每个节点请求Redis,在原本的DTO对象包装一层上下文,用于存放两个省份Id,只在第一次需要使用时进行请求(职责链里的共享状态)。
2.后续的运费计算中只涉及到三个字段的使用,也不存在修改的需求,只筛选出所需要用到的字段转JSON字符串存储Redis。
3.缓存一致性,修改saveOrUpdateDTO方法更新数据库后删除模板缓存(城市id到省份id映射一般不变)。原则上可以暂缓请求
4.可能的缓存穿透,由于修改并不频繁重复更新不会引起数据错误,但更新Redis操作目前没有上锁,可能使得并发下热点城市更新线程较多。
5.缓存内容:a.城市Id到省份Id映射 b.以类型+运输类型+关联城市为key对应的模板数据(三个字段)

实现

 

相关UT与效果

UT

1.创建上海与安徽合肥间的跨省模板(自定义类型)
2.更新上海与安徽合肥间的跨省模板
notion image

执行效果

notion image
notion image
notion image

Redis相关数据

城市到省份映射x2 + 模板数据x1 均为string类型
notion image
删除缓存后
notion image

城市到省份映射

前缀+城市id为key 省份id为value
 
上海
notion image
安徽合肥
notion image
模板数据
notion image
 

MySQL数据

notion image
notion image
 
[神领物流]项目复盘-环境搭建GopherCon 2018 - Golang调度器/GMP笔记
Loading...
2024-2025CamelliaV.

CamelliaV | Java;CV;ACGN


  1. 1 BRIGHTEST HEART オグリキャップ (CV.高柳知葉)
  2. 2 Raven Oliver Good
  3. 3 Against the Tide(逆潮) 鸣潮先约电台/Forts
  4. 4 给予你的爱 Xi YuaN/Digital Vengeance/唢清
  5. 5 スペルビア帝国/夜 平松建治
  6. 6 Imagination QQHHh
  7. 7 virtues QQHHh
  8. 8 Tricolor (short ver.) Digital Vengeance/44
  9. 9 港口夜 - 四周年 月代彩
  10. 10 神よ、その黄昏よ 金﨑猛
  11. 11 絆炎 (English Ver) Katherine Eames
  12. 12 ラストエンゲージ~祈りの呪文 馬場泰久
  13. 13 an evening calm fripSide
  14. 14 フレスベルグの少女~風花雪月~ Caro
  15. 15 Answer 北原春希/小木曽雪菜
  16. 16 Kiss Kiss Kiss BENI
  17. 17 远航高歌 染音若蔡/阿南
  18. 18 Sentimental Blue Trident
  19. 19 目指す先にあるもの Falcom Sound Team J.D.K.
  20. 20 Night City r e l/Artemis Delta
  21. 21 Gimme×Gimme P*Light/Giga/初音ミク/鏡音リン
  22. 22 桃幻浪漫 Airots/Active Planets & AUGUST
  23. 23 DESIRE 美郷あき
  24. 24 镜花堂(feat.芬璃尔) 幻塔手游/Rux
  25. 25 she was sitting under the osmanthus tree 梶浦由記
BRIGHTEST HEART - オグリキャップ (CV.高柳知葉)
00:00 / 04:02