创建时间:2022年09月30日 07:41:39
描 述:本次的Api是对之前的研发进行重构
技 术 栈:SpringBoot、SpringCloudAlibaba(Nacos)、Mybatis Plus(自动生成代码且预置了一些增删改查)
common作为模块,不是微服务,其作用大致如下。
- 作为一般微服务的父pom,因此该pom依赖了一些常用的依赖库,例如springcloud、springboot、lombok等。
- 作为多个微服务共同使用的工具类、bean集合,例如 Response、Response.buildXXXX、ResStatusEnum等。
- 一些框架工具也放在此模块中,比如鉴权的拦截工具类、自定义异常拦截等。
本服务作为所有微服务的网关服务。
用户微服务
记账微服务
销户一般请求的是用户微服务,进行删除账户,由于其它的微服务会涉及到存储用户的信息,因此也需要同步删除其他微服务的用户信息;
实现的方式有两种:
- RPC
- 消息队列 MQ
由于销户涉及的微服务比较多,使用RPC的方式明显薄弱,因此选择MQ是最佳的选择。
https://www.baomidou.com/pages/10c804/
根据用户id查询当月下,收入和支出的账单金额。
1.使用group by 对收入和支出进行分组。
2.使用date_format方法指定请求年月。
3.使用聚合函数sum求值。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMM", Locale.CHINA); String format = dtf.format(LocalDate.now()); QueryWrapper<RecordAccountDO> objectQueryWrapper = new QueryWrapper<>(); objectQueryWrapper.select("classify_type classifyType, SUM(bill_money) as money") .apply("date_format(record_time, '%Y%m') = {0}", format) .groupBy("classify_type"); List<Map<String, Object>> maps = recordAccountMapper.selectMaps(objectQueryWrapper);
SELECT classify_type classifyType, SUM(bill_money) as money FROM t_record_account WHERE (date_format(record_time, '%Y%m') = ?) GROUP BY classify_type
记账(t_record_account)表中有一个字段分类ID(classifyId),分类表中(t_classify)表中有一个字段图标ID(icon_id)。
通过t_record_account查询出记账列表 --> 通过 classifyId 查询对应分类 --> 通过 icon_id 查询对应的图标对象 --> 将icon对象放入,t_record_account。
private void handlerIcon(List<DayRecordAccountObject> dayRecordAccountObjects) { List<Long> classifyIds = dayRecordAccountObjects.stream() .map(DayRecordAccountObject::getClassifyId).collect(Collectors.toList()); // 从分类列表中剥离iconId,然后通过iconId 查训icon对象 List<ClassifyDO> classifyDOS = classifyMapper .selectList(new QueryWrapper<ClassifyDO>().in("classify_id", classifyIds)); List<IconDO> iconDOS = iconMapper.selectList(new QueryWrapper<IconDO>() .in("icon_id", classifyDOS.stream().map(ClassifyDO::getIconId).collect(Collectors.toList()))); // 剥离出 (classifyId, icon对象) List<Map<Long, Icon>> iconMaps = classifyDOS.stream().flatMap(classifyDO -> iconDOS.stream() .filter(iconDO -> !ObjectUtils.notEqual(iconDO.getIconId(), classifyDO.getIconId())) .map(iconDO -> { // map存放 (classifyId, Icon对象) Map<Long, Icon> map = new HashMap<>(); map.put(classifyDO.getClassifyId(), CommonUtil.copyProperties(iconDO, new Icon())); return map; })) .collect(Collectors.toList()); // 把icon对象塞入 DayRecordAccountObject 对象中 dayRecordAccountObjects.forEach(dayRecordAccountObject -> { Optional<Icon> iconOptional = iconMaps.stream() .filter(iconMap -> ObjectUtils.isNotEmpty(iconMap.get(dayRecordAccountObject.getClassifyId()))) .map(iconMap -> iconMap.get(dayRecordAccountObject.getClassifyId())).findAny(); dayRecordAccountObject.setIcon(iconOptional.orElse(null)); }); }
1.通过classifyId查询出来的icon对象,使用map对象将 key=classifyId,value=iconObject 进行存储。
2.通过dayRecordAccountObjects遍历出来的对象进行添加icon图标对象。
jwt(Json Web Token):jwt用于web与后台交互进行校验的token。
jwt由三部分构成,分别为头部、载荷、签名构成。三部分中间使用 "." 进行分隔。
JWTString=Base64(Header).Base64(Payload).HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
String compact = Jwts.builder().setSubject("User Login Jwt Token") .claim("userId", 45) .claim("userName", "rollin") .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 2000)) .signWith(SignatureAlgorithm.HS256, "recordaccount.jwt.key") .compact();
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJVc2VyIExvZ2luIEp3dCBUb2tlbiIsInVzZXJJZCI6NDUsInVzZXJOYW1lIjoicm9sbGluIiwiaWF0IjoxNjY1MTE4OTE5LCJleHAiOjE2NjUxMTg5MjF9.p8XdYXk3-tIudJP8kQTnoCuF90iLIshb-gpisKmlY5o
构成示例
eyJhbGciOiJIUzI1NiJ9
{"alg":"HS256"}eyJzdWIiOiJVc2VyIExvZ2luIEp3dCBUb2tlbiIsInVzZXJJZCI6NDUsInVzZXJOYW1lIjoicm9sbGluIiwiaWF0IjoxNjY1MTE4OTE5LCJleHAiOjE2NjUxMTg5MjF9
{"sub":"User Login Jwt Token","userId":45,"userName":"rollin","iat":1665118919,"exp":1665118921}p8XdYXk3-tIudJP8kQTnoCuF90iLIshb-gpisKmlY5o
签名算法
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
public class CartVO { /** * 购物项 */ private List<CartItemVO> cartItems; /** * 购买总件数 */ private Integer totalNum; /** * 购物车总价格 */ private BigDecimal totalPrice; /** * 购物车实际支付价格 */ private BigDecimal realPayPrice; /** * 总件数 * @return */ public Integer getTotalNum() { if(this.cartItems!=null){ int total = cartItems.stream().mapToInt(CartItemVO::getBuyNum).sum(); return total; } return 0; } /** * 总价格 * @return */ public BigDecimal getTotalPrice() { BigDecimal amount = new BigDecimal("0"); if(this.cartItems!=null){ for(CartItemVO cartItemVO : cartItems){ BigDecimal itemTotalAmount = cartItemVO.getTotalAmount(); amount = amount.add(itemTotalAmount); } } return amount; } /** * 购物车里面实际支付的价格 * @return */ public BigDecimal getRealPayPrice() { BigDecimal amount = new BigDecimal("0"); if(this.cartItems!=null){ for(CartItemVO cartItemVO : cartItems){ BigDecimal itemTotalAmount = cartItemVO.getTotalAmount(); amount = amount.add(itemTotalAmount); } } return amount; } public List<CartItemVO> getCartItems() { return cartItems; } public void setCartItems(List<CartItemVO> cartItems) { this.cartItems = cartItems; } }
通过自定义Getter方法,将List中的内容进行归并计算;例如通过cartItems 计算出 totalNum、 totalPrice、 realPayPrice。
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency>
将 @Autowird 改为 @Resource 即可。
为 @Autowired 注解设置required = false;他表达的意思是:使用 @Autowired 注解不再去校验userMapper是否存在了,也就不会有警告了
把IDEA的警告关闭掉;不建议使用,因为Idea的灵魂就是提示,去掉了就没多大灵魂所在。