范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

基于DDD的微服务落地

  DDD四层架构
  对实时性要求高的强一致性业务场景,可采取分布式事务。分布式事务有性能代价,在设计时需要平衡考虑业务拆分、数据一致性、性能和实现的复杂度,尽量避免分布式事务的产生。
  领域事件驱动的异步方式是分布式架构常用的设计方式,可以解决非实时性场景下的数据最终一致性问题。基于消息中间件的领域事件发布和订阅,可以很好的解耦微服务。通过削峰填谷,实现读写分离、减轻数据库实时访问压力,提高业务吞吐量和业务处理能力。
  DDD设计思想和方法
  DDD设计思想和方法
  聚合根
  聚合根包括聚合根属性、关联的实体和值对象以及自身的业务行为等。通过引用实体和值对象,协调聚合内的多个实体,在聚合根类方法中完成多实体的复杂业务逻辑。
  充血模型:即领域模型模式。有自己的业务行为(方法),如下充血模型中提供getDuration、addHistoryApprovalInfo等方法。
  贫血模型:即事务脚本模式。只有对象属性和setter/getter。 @Data public class Leave {     String id;     Applicant applicant;     Approver approver;     LeaveType type;     Status status;     Date startTime;     Date endTime;     long duration;     //审批领导的最大级别     int leaderMaxLevel;     ApprovalInfo currentApprovalInfo;     List historyApprovalInfos;       public long getDuration() {         return endTime.getTime() - startTime.getTime();     }       public Leave addHistoryApprovalInfo(ApprovalInfo approvalInfo) {         if (null == historyApprovalInfos)             historyApprovalInfos = new ArrayList<>();         this.historyApprovalInfos.add(approvalInfo);         return this;     }       public Leave create(){         this.setStatus(Status.APPROVING);         this.setStartTime(new Date());         return this;     }       public Leave agree(Approver nextApprover){         this.setStatus(Status.APPROVING);         this.setApprover(nextApprover);         return this;     }       public Leave reject(Approver approver){         this.setApprover(approver);         this.setStatus(Status.REJECTED);         this.setApprover(null);         return this;     }       public Leave finish(){         this.setApprover(null);         this.setStatus(Status.APPROVED);         this.setEndTime(new Date());         this.setDuration(this.getEndTime().getTime() - this.getStartTime().getTime());         return this;     } }
  实体
  实体有自己的属性和关联的值对象。@Data public class ApprovalInfo {     String approvalInfoId;     Approver approver;     ApprovalType approvalType;     String msg;     long time; }
  值对象public enum Status {     APPROVING, APPROVED, REJECTED } @Data @AllArgsConstructor @NoArgsConstructor @Builder public class Approver {     String personId;     String personName;     int level;        public static Approver fromPerson(Person person){         Approver approver = new Approver();         approver.setPersonId(person.getPersonId());         approver.setPersonName(person.getPersonName());         approver.setLevel(person.getRoleLevel());         return approver;     } }
  领域对象
  如果一个业务行为由多个实体对象参与完成,就将该业务逻辑放在领域服务中实现。
  实体方法:完成单一实体自身的业务逻辑,是相对简单的原子业务逻辑。
  领域服务:由多个实体组合的相对复杂的业务逻辑。@Service @Slf4j public class LeaveDomainService {     @Autowired     EventPublisher eventPublisher;     @Autowired     ILeaveRepository iLeaveRepository;     @Autowired     LeaveFactory leaveFactory;       @Transactional     public void createLeave(Leave leave, int leaderMaxLevel, Approver approver) {         leave.setLeaderMaxLevel(leaderMaxLevel);         leave.setApprover(approver);         leave.create();         iLeaveRepository.save(leaveFactory.createLeavePO(leave));         LeaveEvent event = LeaveEvent.create(LeaveEventType.CREATE_EVENT, leave);         iLeaveRepository.saveEvent(leaveFactory.createLeaveEventPO(event));         eventPublisher.publish(event);     }       @Transactional     public void updateLeaveInfo(Leave leave) {         LeavePO po = leaveRepositoryInterface.findById(leave.getId());         if (null == po) {             throw new RuntimeException("leave不存在");         }         iLeaveRepository.save(leaveFactory.createLeavePO(leave));     }       @Transactional     public void submitApproval(Leave leave, Approver approver) {         LeaveEvent event;         if ( ApprovalType.REJECT == leave.getCurrentApprovalInfo().getApprovalType()) {             leave.reject(approver);             event = LeaveEvent.create(LeaveEventType.REJECT_EVENT, leave);         } else {             if (approver != null) {                 leave.agree(approver);                 event = LeaveEvent.create(LeaveEventType.AGREE_EVENT, leave);             } else {                 leave.finish();                 event = LeaveEvent.create(LeaveEventType.APPROVED_EVENT, leave);             }         }         leave.addHistoryApprovalInfo(leave.getCurrentApprovalInfo());         iLeaveRepository.save(leaveFactory.createLeavePO(leave));         iLeaveRepository.saveEvent(leaveFactory.createLeaveEventPO(event));         eventPublisher.publish(event);     }       public Leave getLeaveInfo(String leaveId) {         LeavePO leavePO = iLeaveRepository.findById(leaveId);         return leaveFactory.getLeave(leavePO);     }       public List queryLeaveInfosByApplicant(String applicantId) {         List leavePOList = iLeaveRepository.queryByApplicantId(applicantId);         return leavePOList.stream()                 .map(leavePO -> leaveFactory.getLeave(leavePO))                 .collect(Collectors.toList());     }       public List queryLeaveInfosByApprover(String approverId) {         List leavePOList = iLeaveRepository.queryByApproverId(approverId);         return leavePOList.stream()                 .map(leavePO -> leaveFactory.getLeave(leavePO))                 .collect(Collectors.toList());     } }
  在应用服务组合不同聚合的领域服务时,通过Id或参数传参,尽量避免领域对象传参,以减少聚合之间的耦合度。
  领域事件
  领域事件基类@Data public class DomainEvent {         String id;          Date timestamp;          String source;          String data; }@Service public class EventPublisher {         public void publish(LeaveEvent event){             //send to MQ             //mq.send(event);         } }
  领域事件实体@Data public class LeaveEvent extends DomainEvent {          LeaveEventType leaveEventType;          public static LeaveEvent create(LeaveEventType eventType, Leave leave){               LeaveEvent event = new LeaveEvent();               event.setId(IdGenerator.nextId());               event.setLeaveEventType(eventType);               event.setTimestamp(new Date());               event.setData(JSON.toJSONString(leave));               return event;     	} }
  领域事件的执行逻辑:执行业务逻辑,产生领域事件。调用仓储接口,完成业务数据持久化。调用仓储接口,完成事件数据持久化。完成领域事件发布。
  仓储模式
  仓储接口public interface ILeaveRepository {         void save(LeavePO leavePO);          void saveEvent(LeaveEventPO leaveEventPO);          LeavePO findById(String id);          List queryByApplicantId(String applicantId);          List queryByApproverId(String approverId); }
  仓储实现@Repository public class LeaveRepositoryImpl implements ILeaveRepository {       @Autowired       LeaveDao leaveDao;        @Autowired       ApprovalInfoDao approvalInfoDao;        @Autowired       LeaveEventDao leaveEventDao;        public void save(LeavePO leavePO) {             leaveDao.save(leavePO);             leavePO.getHistoryApprovalInfoPOList().forEach(approvalInfoPO -> approvalInfoPO.setLeaveId(leavePO.getId()));             approvalInfoDao.saveAll(leavePO.getHistoryApprovalInfoPOList());       }        public void saveEvent(LeaveEventPO leaveEventPO){             leaveEventDao.save(leaveEventPO);       }        @Override       public LeavePO findById(String id) {             return leaveDao.findById(id)             .orElseThrow(() -> new RuntimeException("leave不存在"));       }        @Override       public List queryByApplicantId(String applicantId) {               List leavePOList = leaveDao.queryByApplicantId(applicantId);               leavePOList.forEach(leavePO -> {               List approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());               leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);               });               return leavePOList;       }        @Override       public List queryByApproverId(String approverId) {               List leavePOList = leaveDao.queryByApproverId(approverId);               leavePOList.forEach(leavePO -> {               List approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());               leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);               });               return leavePOList;       } }
  这里为什么没有使用一对多、多对对呢?时间紧任务重或者并发量不高时可以使用,后期并发量起来了后,数据库将成为瓶颈。
  JPA/Hibernate注解:@OneToMany、@ManyToOne、@ManyToMany;
  Mybatis注解:
  @Results(id="", value={@Result(column="", property="", jdbcType=JdbcType.INTEGER),
  @Result(column="", property="", javaType=xx.class,one=@One(select="com.xx..XxMapper.selectById"))
  })
  或
  @Results(id="",value = { @Result(property = "", column = ""),
  @Result(property = "xxList", javaType=List.class, many=@Many(select=""), column = "")});
  Mybatis xml: association、collection。
  工厂模式
  工厂模式将与业务无关的职能从聚合根中剥离,放在工厂中统一创建和初始化。//可考虑使用MapStruct @Service public class LeaveFactory {       public LeavePO createLeavePO(Leave leave) {             LeavePO leavePO = new LeavePO();             leavePO.setId(UUID.randomUUID().toString());             leavePO.setApplicantId(leave.getApplicant().getPersonId());             leavePO.setApplicantName(leave.getApplicant().getPersonName());             leavePO.setApproverId(leave.getApprover().getPersonId());             leavePO.setApproverName(leave.getApprover().getPersonName());             leavePO.setStartTime(leave.getStartTime());             leavePO.setStatus(leave.getStatus());             List historyApprovalInfoPOList = approvalInfoPOListFromDO(leave);             leavePO.setHistoryApprovalInfoPOList(historyApprovalInfoPOList);             return leavePO;       }        public Leave getLeave(LeavePO leavePO) {           Leave leave = new Leave();           Applicant applicant = Applicant.builder()                   .personId(leavePO.getApplicantId())                   .personName(leavePO.getApplicantName())                   .build();           leave.setApplicant(applicant);           Approver approver = Approver.builder()                 .personId(leavePO.getApproverId())                 .personName(leavePO.getApproverName())                 .build();           leave.setApprover(approver);           leave.setStartTime(leavePO.getStartTime());           leave.setStatus(leavePO.getStatus());           List approvalInfos = getApprovalInfos(leavePO.getHistoryApprovalInfoPOList());           leave.setHistoryApprovalInfos(approvalInfos);           return leave;       }        public LeaveEventPO createLeaveEventPO(LeaveEvent leaveEvent){             LeaveEventPO eventPO = new LeaveEventPO();             eventPO.setLeaveEventType(leaveEvent.getLeaveEventType());             eventPO.setSource(leaveEvent.getSource());             eventPO.setTimestamp(leaveEvent.getTimestamp());             eventPO.setData(JSON.toJSONString(leaveEvent.getData()));             return eventPO;       }        private List approvalInfoPOListFromDO(Leave leave) {             return leave.getHistoryApprovalInfos()             .stream()             .map(this::approvalInfoPOFromDO)             .collect(Collectors.toList());       }        private ApprovalInfoPO approvalInfoPOFromDO(ApprovalInfo approvalInfo){             ApprovalInfoPO po = new ApprovalInfoPO();             po.setApproverId(approvalInfo.getApprover().getPersonId());             po.setApproverLevel(approvalInfo.getApprover().getLevel());             po.setApproverName(approvalInfo.getApprover().getPersonName());             po.setApprovalInfoId(approvalInfo.getApprovalInfoId());             po.setMsg(approvalInfo.getMsg());             po.setTime(approvalInfo.getTime());             return po;       }        private ApprovalInfo approvalInfoFromPO(ApprovalInfoPO approvalInfoPO){             ApprovalInfo approvalInfo = new ApprovalInfo();             approvalInfo.setApprovalInfoId(approvalInfoPO.getApprovalInfoId());             Approver approver = Approver.builder()             .personId(approvalInfoPO.getApproverId())             .personName(approvalInfoPO.getApproverName())             .level(approvalInfoPO.getApproverLevel())             .build();             approvalInfo.setApprover(approver);             approvalInfo.setMsg(approvalInfoPO.getMsg());             approvalInfo.setTime(approvalInfoPO.getTime());             return approvalInfo;       }  	private List getApprovalInfos(List approvalInfoPOList){         return approvalInfoPOList.stream()         .map(this::approvalInfoFromPO)         .collect(Collectors.toList());     } }
  服务的组合和编排
  应用层的应用服务主要完成领域服务的组合与编排。@Service public class LeaveApplicationService {     @Autowired     LeaveDomainService leaveDomainService;     @Autowired     PersonDomainService personDomainService;     @Autowired     ApprovalRuleDomainService approvalRuleDomainService;       /**      * 创建一个请假申请并为审批人生成任务      * @param leave      */     public void createLeaveInfo(Leave leave){         int leaderMaxLevel = approvalRuleDomainService.getLeaderMaxLevel(leave.getApplicant().getPersonType(), leave.getType().toString(), leave.getDuration());         Person approver = personDomainService.findFirstApprover(leave.getApplicant().getPersonId(), leaderMaxLevel);         leaveDomainService.createLeave(leave, leaderMaxLevel, Approver.fromPerson(approver));     }       /**      * 更新请假单基本信息      * @param leave      */     public void updateLeaveInfo(Leave leave){         leaveDomainService.updateLeaveInfo(leave);     }       /**      * 提交审批,更新请假单信息      * @param leave      */     public void submitApproval(Leave leave){         //find next approver         Person approver = personDomainService.findNextApprover(leave.getApprover().getPersonId(), leave.getLeaderMaxLevel());         leaveDomainService.submitApproval(leave, Approver.fromPerson(approver));     }       public Leave getLeaveInfo(String leaveId){         return leaveDomainService.getLeaveInfo(leaveId);     }       public List queryLeaveInfosByApplicant(String applicantId){         return leaveDomainService.queryLeaveInfosByApplicant(applicantId);     }       public List queryLeaveInfosByApprover(String approverId){         return leaveDomainService.queryLeaveInfosByApprover(approverId);     } }
  服务接口的提供
  facade门面接口主要抽象出Controller Api作为OpenFeign调用的接口门面类。/** * @author lyonardo * @Description * @createTime 2020年03月08日 15:06:00 */ @FeignClient(name = "leave-service", path = "/leave") public interface LeaveFeignClient {       @PostMapping("/submit")       Response submitApproval(LeaveDTO leaveDTO);        @PostMapping("/{leaveId}")       Response findById(@PathVariable String leaveId);       /**       * 根据申请人查询所有请假单       * @param applicantId       * @return       */       @PostMapping("/query/applicant/{applicantId}")       Response queryByApplicant(@PathVariable String applicantId);       /**       * 根据审批人id查询待审批请假单(待办任务)       * @param approverId       * @return       */       @PostMapping("/query/approver/{approverId}")       Response queryByApprover(@PathVariable String approverId)(); }
  实现类@RestController @RequestMapping("/leave") @Slf4j public class LeaveApi {     @Autowired     LeaveApplicationService leaveApplicationService;      @PostMapping("/create")     public Response createLeaveInfo(LeaveDTO leaveDTO){         Leave leave = LeaveAssembler.toDO(leaveDTO);         leaveApplicationService.createLeaveInfo(leave);         return Response.ok();     }      @PutMapping("/update")     public Response updateLeaveInfo(LeaveDTO leaveDTO){         Leave leave = LeaveAssembler.toDO(leaveDTO);         leaveApplicationService.updateLeaveInfo(leave);         return Response.ok();     }      @PostMapping("/submit")     public Response submitApproval(LeaveDTO leaveDTO){         Leave leave = LeaveAssembler.toDO(leaveDTO);         leaveApplicationService.submitApproval(leave);         return Response.ok();     }      @PostMapping("/{leaveId}")     public Response findById(@PathVariable String leaveId){       Leave leave = leaveApplicationService.getLeaveInfo(leaveId);       return Response.ok(LeaveAssembler.toDTO(leave));     }      /**     * 根据申请人查询所有请假单     * @param applicantId     * @return     */     @PostMapping("/query/applicant/{applicantId}")     public Response queryByApplicant(@PathVariable String applicantId){         List leaveList = leaveApplicationService.queryLeaveInfosByApplicant(applicantId);         List leaveDTOList = leaveList.stream().map(leave -> LeaveAssembler.toDTO(leave)).collect(Collectors.toList());         return Response.ok(leaveDTOList);     }      /**     * 根据审批人id查询待审批请假单(待办任务)     * @param approverId     * @return     */     @PostMapping("/query/approver/{approverId}")     public Response queryByApprover(@PathVariable String approverId){             List leaveList = leaveApplicationService.queryLeaveInfosByApprover(approverId);             List leaveDTOList = leaveList.stream().map(leave -> LeaveAssembler.toDTO(leave)).collect(Collectors.toList());             return Response.ok(leaveDTOList);       } }
  数据组装层
  LeaveAssembler
  //可使用MapStruct做对象转换和组装public class LeaveAssembler { 	public static LeaveDTO toDTO(Leave leave){         LeaveDTO dto = new LeaveDTO();         dto.setLeaveId(leave.getId());         dto.setLeaveType(leave.getType().toString());         dto.setStatus(leave.getStatus().toString());         dto.setStartTime(DateUtil.formatDateTime(leave.getStartTime()));         dto.setEndTime(DateUtil.formatDateTime(leave.getEndTime()));         dto.setCurrentApprovalInfoDTO(ApprovalInfoAssembler.toDTO(leave.getCurrentApprovalInfo()));         List historyApprovalInfoDTOList = leave.getHistoryApprovalInfos()         .stream()         .map(historyApprovalInfo -> ApprovalInfoAssembler.toDTO(leave.getCurrentApprovalInfo()))         .collect(Collectors.toList());         dto.setHistoryApprovalInfoDTOList(historyApprovalInfoDTOList);         dto.setDuration(leave.getDuration());         return dto; 	}  	public static Leave toDO(LeaveDTO dto){         Leave leave = new Leave();         leave.setId(dto.getLeaveId());         leave.setApplicant(ApplicantAssembler.toDO(dto.getApplicantDTO()));         leave.setApprover(ApproverAssembler.toDO(dto.getApproverDTO()));         leave.setCurrentApprovalInfo(ApprovalInfoAssembler.toDO(dto.getCurrentApprovalInfoDTO()));         List historyApprovalInfoDTOList = dto.getHistoryApprovalInfoDTOList()         .stream()         .map(ApprovalInfoAssembler::toDO)         .collect(Collectors.toList());         leave.setHistoryApprovalInfos(historyApprovalInfoDTOList);         return leave; 	} }

看似帅气,实则脱发严重!沙溢彭于晏白敬亭,个个心酸又好笑文丨2号探秘人编辑丨2号探秘人当今社会,要问最让年轻人焦虑的问题是什么?回答之一,必有脱发。根据卫健委发布的一组数据,我国脱发人群数量已经超过2。5亿。其中,年轻人是脱发的主力军,双十一后,教你如何防范这些陷阱一年一度的双十一刚刚过去,许多消费者的购物战果还在递送当中,然而骗子也在伺机而动。对于下列虚假招数,消费者需要慧眼识别,防止一不留神踏入陷阱。虚假客服,诱导客户办贷款前不久,林阿姨散文秋去冬来可入诗,凡尘冷暖皆自然作者子墨时光过得真快,季节一晃就老了,一个转身,在不经意间,我们又走过了一季秋天。仿佛,秋天里的许多的故事,还来不及细品,一个季节离去,另一个季节无缝衔接,秋天就这样悄然无声地滑了遇见就好了,余生就算了不是所有的相遇,都能开花结果。在感情的因果里,出场顺序很重要,最先出现的人,不一定能陪你走到最后。很多感情,都败给了年轻很多遗憾,只恨相遇太晚。太早的遇见,常常热情大于爱情,却又想生活就是一个圆至美连云港的花果山垂钓人生就是一个圆,从起点到终点。想起当年的少女时代,便喜欢静静地坐在书桌前看书,写诗。如今,经过三十多年的生活打磨,依旧还是喜欢坐在书桌的一角看书,写字,寻求的是内白发所感所思头条创作挑战赛无论我们知觉与否,时间一直都在悄无声息地流逝,我们的身体和心理也在微妙的回应,白发的出现应证着温水煮青蛙的效应大局已定,黑发失守了。以前看着老人的白发时,想到的更多的如果你有女儿,请告诉她结婚,尽量找这3种家庭01hr有人说婚姻不是一张彩票,哪怕是输了也不能一撕了事。婚姻需要质量,而不是数量。每增加一次婚姻,就会带来一次痛苦。很多父母,总有一种嫁出去就心安了的想法。如果女儿到了三十岁还单新初境第二章最初之战下一念回想着刚刚被结界封印的暗黑之主暗姆斯,若有所思,却始终想不出哪里出现了问题。休息了片刻,一念法师站起,发动次元传送阵。一念进入阵中,来到暗域与星域之间的失却谷。一念站在失却谷暗告别传统,新住宿经济向阳而生日前,亚朵集团在美国纳斯达克IPO上市,成为中国新住宿经济第一股。新住宿经济,成为近十年来中国住宿业变革的一个新注脚。在备受疫情冲击的近三年来,文旅产业加速变革与重构,其中,以轻资万物皆数,这个世界底层逻辑从来都不难,刷新认知,你需要多读书这是宸妈2022年发布的第96篇原创内容全文共计2272字,大约需要24分钟时间阅读这两年看书看得多,个人感觉最大的收获是自己对外界新鲜事物的接受程度变高了,从一个埋头在一线教学的为什么闭环管理的高风险人员可以调整成5天居家健康监测?日前国务院联防联控机制综合组发布关于进一步优化新冠肺炎疫情防控措施科学精准做好防控工作的通知(以下简称通知)公布进一步优化防控工作的二十条措施通知指出党中央对进一步优化防控工作的二
唐太宗为什么害怕宰相房玄龄的夫人?唐太宗对抗旨的房玄龄夫人大为恼火,让宫女端给房玄龄夫人一杯毒酒,她想都没想一饮而尽。但她并没有被毒酒毒死,反而让唐玄宗对这个女人刮目相看。事情是这样的,房玄龄未发迹当宰相时生过一次蜀汉灭亡后,除了刘禅乐不思蜀外,刘备的其他后代怎么样?公元263年,魏将邓艾从阴平而入,攻克绵竹,杀诸葛瞻父子,刘禅投降。蜀汉灭亡后,刘禅及一些蜀汉大臣被迁往洛阳居住,受封为安乐公。刘禅在洛阳居住,而且过得没心没肺,当司马昭问他安乐公U23国足新年首期集训名单,苏州东吴余隆赟梁伟棚在列扬子晚报网1月28日讯(记者张晨瑆孙云岳张昊)北京时间1月28日,为备战2024年巴黎奥运会预选赛暨U23亚洲杯,国足U23公布2023年首期集训名单。来自中甲苏州东吴队的余隆赟梁鹈鹕3员大将缺阵,字母狂虐鹈鹕内线,斩获50分,率队拿下4连胜北京时间1月30日,NBA常规赛继续进行,雄鹿主场135110大胜鹈鹕。此役雄鹿字母哥50分13篮板4助攻,霍勒迪17分7篮板6助攻,洛佩斯15分8篮板3助攻鹈鹕这边阿尔瓦拉多18豫媒河南嵩山龙门欠薪问题已解决,新赛季准入没有任何问题直播吧1月30日讯据郑州日报报道,河南嵩山龙门全队的欠薪问题已经解决,因此新赛季准入已经没有任何问题。嵩山龙门集训时间还未敲定,包括多名外援和内援的合同已经到期,能否继续为河南效力一个ampampquot缺失的环节ampampquot研究人员揭示了复杂生命形式起源的重要组成部分是什么导致了地球上复杂生物体的出现?这是生物学中一个重要的未回答的问题。维也纳大学ChristaSchleper团队和苏黎世联邦理工学院MartinPilhofer团队的研究人员已盘点流浪地球2中的互联网技术,人工智能将带来伦理挑战大家有没有看流浪地球2电影,有没有被电影中的特效震撼到?有没有被电影中出现的先进科技震撼到?这篇文章给大家盘点下流浪地球2出现的与互联网相关的技术。流浪地球1全球互联网全球互联网,专访埃及中国问题专家看好广东经济发展和投资合作的前景1月28日上午,广东全省高质量发展大会在广州召开。这是近年来广东召开的最大规模的会议,为广东经济高质量发展描绘奋进蓝图。中国问题专家埃及贝尼苏韦夫大学政治学教授纳迪娅希勒米(Nad春节十堰城区170多个兔宝宝报到有父母给女儿取名初一正月初一,国药东风总医院首个兔宝宝降生,全家人喜气洋洋。秦楚网讯(十堰晚报)文图记者张贞林特约记者蒋辉通讯员罗芳报道2023年兔年新春的钟声敲响,人们或与家人温馨相伴,或与朋友跨年新正如意泰国中式拜年里的血脉亲情新正如意,新年发财!泰国总理巴育不久前在泰国中部华人聚居的叻武里府出席春节庆祝活动时用中文说道。泰国民众素有庆祝春节的传统,新正如意一直以来都是泰国人的春节口头禅,使用频率大大超过这个时尚玩具暗藏风险,爸爸玩无人机竟意外划伤女儿脸武汉晚报讯(记者王春岚通讯员高琛琛)近年来,无人机受到摄影爱好者的青睐,成为时尚装备之一。今年春节,有摄影爱好者带孩子到户外使用无人机拍摄,结果无人机降落时意外划伤女儿的脸。1月2