创建时间: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的灵魂就是提示,去掉了就没多大灵魂所在。