需求
对于一个微服务接口,需要对返回结果根据真实名字做升序。
服务引用较多,大几十。就想其他方面解决问题。
问个AI
微服务之间调用使用openfeign,我现在需要对于一个模块的服务,返回需要排序,openfeign有没有什么可以在服务正常调用返回后,统一处理排序一下
在使用 OpenFeign 进行微服务之间的调用时,OpenFeign 本身并不直接提供对返回结果排序的功能。但是你可以在服务消费者端实现这一功能。以下是一些建议的方法:
-
客户端排序: 在 Feign 客户端接收到响应后,在业务逻辑层中对接收到的数据进行排序。这是最简单直接的方法,但可能不是最高效的,特别是当数据量较大时。
-
自定义解码器(Decoder): OpenFeign 允许你自定义
Decoder
来处理从远程服务接收到的响应。你可以创建一个自定义的Decoder
,它在将响应体转换为 Java 对象之后再执行排序操作。这可以确保所有通过该 Feign 客户端接收的响应都会被自动排序。 -
AOP 切面编程: 使用 Spring AOP 创建一个切面,在 Feign 客户端调用返回之后但在业务逻辑处理之前,拦截方法的返回值并对其进行排序。这种方法的好处是它可以横切多个 Feign 客户端而无需修改每个客户端的具体实现。
-
响应包装模式: 将所有 Feign 客户端的返回类型封装到一个通用的包装类中,并在这个包装类中实现排序逻辑。这样所有的服务调用返回的结果都可以通过这个包装类来进行统一处理。
-
服务端排序: 如果排序逻辑对于所有消费者都是一致的,那么最好是在服务端完成排序。这种方式减少了客户端的负担,并且保证了所有客户端得到的都是已经排好序的数据。
选择哪种方式取决于你的具体需求、代码库的现状以及团队的偏好。如果你希望在不改变现有接口的前提下添加排序功能,那么自定义解码器或 AOP 可能是最合适的选择。如果这是一个新项目或者你可以修改接口,那么考虑服务端排序可能是更优的选择。
毫无疑问,2,3 是比较符合我这个需求。看了2的实现,感觉较为复杂。还是使用AOP去实现
代码
/**
* @author cmy
* @date 2025/1/20 15:30
*/
@Aspect
@Component
public class CommonSortingAspect {
@AfterReturning(
pointcut = "execution(* com.XXX.common.CommonService.getUserList*(..))",
returning = "result"
)
public void sortUsersByName(JoinPoint joinPoint, List<SysUserDTO> result) {
if (result != null && !result.isEmpty()) {
result.sort(Comparator.comparing(SysUserDTO::getRealName, new PinyinComparator()));
}
}
}
这是使用了Aspect通配符来匹配 作用的方法,刚好命名比较规范,就是以getUserList为开头的方法名,参数各异。
以下是PinyinComparator比较器
public class PinyinComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
if (s1 == null || s2 == null) {
return s1 == null ? (s2 == null ? 0 : -1) : 1;
}
int minLength = Math.min(s1.length(), s2.length());
for (int i = 0; i < minLength; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 == c2) {
continue;
}
if (isChinese(c1) && isChinese(c2)) {
String pinyin1 = getFirstPinyinLetter(c1).toUpperCase();
String pinyin2 = getFirstPinyinLetter(c2).toUpperCase();
int result = pinyin1.compareTo(pinyin2);
if (result != 0) {
return result;
}
} else {
return Character.compare(c1, c2);
}
}
return Integer.compare(s1.length(), s2.length());
}
public static boolean isChinese(char ch) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(ch);
return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION;
}
private String getFirstPinyinLetter(char ch) {
try {
String pinyin = PinyinUtil.getPinyin(ch);
if (pinyin != null && !pinyin.isEmpty()) {
return pinyin.substring(0, 1);
}
} catch (Exception e) {
e.printStackTrace();
}
return String.valueOf(ch);
}
}
中文名第一个重复会对比第二个,以此类推