本文源碼:GitHub·點這裏 || GitEE·點這裏git
更新進度(共6節):
github
01:項目技術選型簡介,架構圖解說明
02:業務架構設計,系統分層管理
03:數據庫選型,業務數據設計規劃
04:中間件集成,公共服務管理
中間件是基礎軟件的一類, 屬於複用性極高的軟件。處於操做系統軟件與應用程序的之間。是一種獨立的系統軟件,也能夠是公共的服務程序,分佈式架構系統藉助中間件,能夠在不一樣的技術之間共享資源,或者不一樣的服務直接傳遞信息。中間件位操做系統之上,管理計算機資源和網絡通信。是鏈接兩個獨立應用程序或獨立系統的軟件,例如:
公共服務,顧名思義就是系統內通用的服務,例如用戶身份驗證,消息發送,監控預警,網關服務等。web
該案例的中間件和公共服務,都是基於Feign
接口統一的方式提供服務。redis
RocketMq
簡介RocketMq
是一款分佈式、隊列模型的消息中間件,有兩個核心角色:消息生產者和消息消費者。做爲高併發系統的核心組件之一,可以幫助業務系統解構提升系統穩定性。spring
@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); } }
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) ; } }
ES
搜索簡介ElasticSearch
是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful
的 web接口。是當前流行的企業級搜索引擎。segmentfault
@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); } }
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); } }
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) ; }
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