本文源碼: "GitHub·點這裡" || "GitEE·點這裡" "01:項目技術選型簡介,架構圖解說明" "02:業務架構設計,系統分層管理" "03:資料庫選型,業務數據設計規劃" 04:中間件集成,公共服務管理 一、中間件簡介 中間件是基礎軟體的一類, 屬於復用性極高的軟體。處於操作系統軟體 ...
本文源碼:GitHub·點這裡 || GitEE·點這裡
更新進度(共6節):
04:中間件集成,公共服務管理
一、中間件簡介
中間件是基礎軟體的一類, 屬於復用性極高的軟體。處於操作系統軟體與應用程式的之間。是一種獨立的系統軟體,也可以是公共的服務程式,分散式架構系統藉助中間件,可以在不同的技術之間共用資源,或者不同的服務直接傳遞信息。中間件位操作系統之上,管理電腦資源和網路通訊。是連接兩個獨立應用程式或獨立系統的軟體,例如:
- 消息隊列中間件,在兩個服務之間進行非同步的消息傳遞;
- 數據緩存中間件,緩存整合系統的熱點數據,提高程式的響應速度;
- Nginx中間件,提供負載均衡,服務代理,等功能;
二、公共服務簡介
公共服務,顧名思義就是系統內通用的服務,例如用戶身份驗證,消息發送,監控預警,網關服務等。
該案例的中間件和公共服務,都是基於Feign
介面統一的方式提供服務。
三、中間件集成
1、消息中間件
RocketMq
簡介
RocketMq
是一款分散式、隊列模型的消息中間件,有兩個核心角色:消息生產者和消息消費者。作為高併發系統的核心組件之一,能夠幫助業務系統解構提高系統穩定性。
- 應用流程
- 消息生產者
@Component
public class MsgSendService {
@Resource
private ProducerConfig producerConfig ;
public void sendMsg (MsgWrap msgWrap) {
producerConfig.sendMsg(msgWrap.getGroup(),msgWrap.getTopic(),
msgWrap.getTag(),msgWrap.getContent());
}
}
- 消息消費者
@Component
@Consumer(group = MsgRoute.husky_group_1,
topic = MsgRoute.husky_topic_1 ,
tag = MsgRoute.husky_tag_1)
public class UserSearchListener implements MsgReadService {
@Resource
private BookEsAnalyFeign bookEsAnalyFeign ;
@Override
public void readMsg(String msg) throws Exception {
LOGGER.info("【用戶搜索消息監聽 Msg】:{}",msg) ;
// 轉發請求數據分析服務
bookEsAnalyFeign.sendBookEsMsg(msg);
}
}
- 提供
Feign
介面
@RestController
public class UserSearchController implements UserSearchFeign {
@Resource
private SendMsgService sendMsgService ;
@Override
public void sendBookSearch(String msgContent) {
MsgWrap msgWrap = new MsgWrap() ;
msgWrap.setContent(msgContent);
msgWrap.setGroup(MsgRoute.husky_group_1);
msgWrap.setTopic(MsgRoute.husky_topic_1);
msgWrap.setTag(MsgRoute.husky_tag_1);
sendMsgService.sendMsg(msgWrap);
}
}
2、緩存中間件
Redis
簡介
Redis
是一個基於記憶體的高性能key-value
資料庫。對高併發系統提供各種場景的支撐:熱點數據緩存,計數器,流量削峰等。
- 應用流程
- 封裝操作方法
@Service
public class RedisServiceImpl implements RedisService {
@Resource
private RedisTemplate<Object,Object> redisTemplate ;
@Override
public boolean set(Object key, Object value) {
boolean redisFlag = true ;
try {
redisTemplate.opsForValue().set(key,value);
} catch (Exception e){
redisFlag = false ;
e.printStackTrace();
}
return redisFlag ;
}
@Override
public boolean set(Object key,Object value, long expire) {
boolean redisFlag = true ;
try {
redisTemplate.opsForValue().set(key,value,expire,TimeUnit.SECONDS);
} catch (Exception e){
redisFlag = false ;
e.printStackTrace();
}
return redisFlag ;
}
@Override
public String get(Object key) {
String value = null ;
try {
value = String.valueOf(redisTemplate.opsForValue().get(key)) ;
} catch (Exception e){
e.printStackTrace();
}
return value ;
}
}
- 提供
Feign
服務
@RestController
public class RedisController implements RedisFeign {
@Resource
private RedisService redisService ;
@Override
public boolean set (String key, String value) {
return redisService.set(key,value) ;
}
@Override
public boolean setTimeOut (String key, String value,long expire){
return redisService.set(key,value,expire) ;
}
@Override
public String get (String key) {
return redisService.get(key) ;
}
}
3、搜素中間件
ES
搜索簡介
ElasticSearch
是一個基於Lucene的搜索伺服器。它提供了一個分散式多用戶能力的全文搜索引擎,基於RESTful
的 web介面。是當前流行的企業級搜索引擎。
- 應用流程
- 封裝操作方法
@Service
public class BookInfoEsServiceImpl implements BookInfoEsService {
@Resource
private BookInfoRepository bookInfoRepository ;
@Override
public void batchSave(List<EsBookInfo> bookInfoList) {
bookInfoRepository.saveAll(bookInfoList) ;
}
@Override
public List<EsBookInfo> queryList() {
Iterable<EsBookInfo> bookInfoIterable = bookInfoRepository.findAll() ;
List<EsBookInfo> esBookInfoList = Lists.newArrayList(bookInfoIterable) ;
if (esBookInfoList == null){
esBookInfoList = new ArrayList<>() ;
}
return esBookInfoList;
}
@Override
public List<EsBookInfo> getByKeyWord(String keyWord) {
QueryStringQueryBuilder builder = new QueryStringQueryBuilder(keyWord);
Iterable<EsBookInfo> bookInfoIterable = bookInfoRepository.search(builder) ;
List<EsBookInfo> esBookInfoList = Lists.newArrayList(bookInfoIterable) ;
if (esBookInfoList == null){
esBookInfoList = new ArrayList<>() ;
}
return esBookInfoList ;
}
}
- 提供
Feign
服務
@RestController
public class BookInfoEsController implements BookInfoEsFeign {
@Resource
private BookInfoEsService bookInfoEsService ;
@Override
public void batchSave(List<EsBookInfo> bookInfoList) {
bookInfoEsService.batchSave(bookInfoList);
}
@Override
public List<EsBookInfo> queryList() {
return bookInfoEsService.queryList();
}
@Override
public List<EsBookInfo> getByKeyWord(String keyWord) {
return bookInfoEsService.getByKeyWord(keyWord);
}
}
4、定時器中間件
Quartz
簡介
Quartz
是由Java
編寫的開源任務調度的框架,通過觸發器設置作業定時運行規則,控制任務的執行時間。其中quartz
集群通過故障切換和負載平衡的功能,能給調度器帶來高可用性和伸縮性。
- 應用流程
@Component("SendMsgJob")
public class SendMsgJob implements TaskJobService {
@Resource
private SendEmailFeign sendEmailFeign ;
@Override
public void run(String param) {
String nowDate = TimeUtil.formatDate(new Date(),TimeUtil.FORMAT_01) ;
LOGGER.info("SendMsgJob Execute Time:{}",nowDate);
sendEmailFeign.sendEmail("","定時郵件通知",""+nowDate);
}
}
四、公共服務管理
1、Token服務
Token
服務簡介
通過一個公共的Token
管理服務,對訪問系統的用戶身份做管理:身份令牌創建,校驗,刷新等。
- 應用流程
- 封裝操作方法
@Service
public class UserTokenServiceImpl implements UserTokenService {
@Resource
private UserBaseMapper userBaseMapper ;
@Resource
private RedisFeign redisFeign ;
@Override
public String getToken(String userName, String passWord) throws Exception {
UserBaseExample example = new UserBaseExample() ;
example.createCriteria().andUserNameEqualTo(userName) ;
UserBase userBase = selectByExample(example) ;
if (userBase != null){
String secrete = userBase.getPassWord() ;
if (secrete.equals(passWord)) {
// 返回 Token
String value = userBase.getId().toString() ;
String publicKeyStr = RsaCryptUtil.getKey(RsaCryptUtil.PUB_KEY) ;
String token = RsaCryptUtil.encrypt(RsaCryptUtil.createPublicKey(publicKeyStr),value.getBytes()) ;
String key = RedisUtil.formatUserTokenKey(userBase.getId()) ;
redisFeign.setTimeOut(key,token, Constant.USER_TOKEN_EXPIRE) ;
return token ;
}
}
return null;
}
@Override
public Integer verifyToken(String token) throws Exception {
String privateKeyStr = RsaCryptUtil.getKey(RsaCryptUtil.PRI_KEY) ;
String userId = RsaCryptUtil.decrypt(RsaCryptUtil.createPrivateKey(privateKeyStr),
RsaCryptUtil.parseBase64Binary(token));
return Integer.parseInt(userId) ;
}
@Override
public boolean refreshToken(String token) throws Exception {
Integer userId = verifyToken(token) ;
if (userId > 0 ){
String key = RedisUtil.formatUserTokenKey(userId) ;
// 判斷Token 是否過期
String cacheToken = redisFeign.get(key) ;
if (StringUtils.isEmpty(cacheToken)){
return false ;
}
redisFeign.setTimeOut(key,token, Constant.USER_TOKEN_EXPIRE) ;
return true ;
}
return false ;
}
}
- 提供
Feign
服務
@FeignClient("MOPSZ-BASIS-TOKEN")
public interface UserTokenFeign {
/**
* 獲取 TOKEN
*/
@PostMapping("/token/getToken")
RespObject getToken (@RequestParam("userName") String userName,
@RequestParam("passWord") String passWord) ;
/**
* 驗證 TOKEN
*/
@PostMapping("/token/verifyToken")
RespObject verifyToken (@RequestParam("token") String token) ;
/**
* 刷新 TOKEN
*/
@PostMapping("/token/refreshToken")
boolean refreshToken (@RequestParam("token") String token) ;
}
2、消息服務
Msg
服務簡介
在一個複雜的系統中,消息通知是一個必備模塊,一般封裝方式主要從下麵兩個方式入手,消息類型:用戶消息,系統消息等,消息接收方式:郵件,簡訊,應用端等。
- 應用流程
- 封裝郵件發送
@Service
public class SendEmailServiceImpl implements SendEmailService {
@Override
public void sendEmail(String receive, String title, String msg) {
try {
EmailUtil.sendEmail01(receive,title,msg);
} catch (Exception e){
e.printStackTrace() ;
LOGGER.info("郵件發送失敗:{}",e.getMessage());
}
}
}
- 提供
Feign
服務
@FeignClient("MOPSZ-BASIS-MSGBOX")
public interface SendEmailFeign {
/**
* 發送Email
*/
@PostMapping("/msgBox/sendEmail")
void sendEmail (@RequestParam("receive") String receive,
@RequestParam("title") String title,
@RequestParam("msg") String msg) ;
}
五、源代碼地址
GitHub·地址
https://github.com/cicadasmile/husky-spring-cloud
GitEE·地址
https://gitee.com/cicadasmile/husky-spring-cloud