请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

这个是ShareService 代码

package com.itmuch.contentcenter.service.content;

import com.itmuch.contentcenter.dao.content.RocketmqTransactionLogMapper;
import com.itmuch.contentcenter.dao.content.ShareMapper;
import com.itmuch.contentcenter.domain.dto.content.ShareAuditDTO;
import com.itmuch.contentcenter.domain.dto.content.ShareDTO;
import com.itmuch.contentcenter.domain.dto.message.UserAddBonusMsgDTO;
import com.itmuch.contentcenter.domain.dto.user.UserDTO;
import com.itmuch.contentcenter.domain.entity.content.RocketmqTransactionLog;
import com.itmuch.contentcenter.domain.entity.content.Share;
import com.itmuch.contentcenter.domain.enums.AuditStatusEnum;
import com.itmuch.contentcenter.feignclient.UserCenterFeignClient;
import com.sun.xml.internal.txw2.IllegalSignatureException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class ShareService {

private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;
private final RocketMQTemplate rocketMQTemplate;
private final ShareMapper shareMapper;
//private final RestTemplate restTemplate;
private final UserCenterFeignClient userCenterFeignClient;
//private final DiscoveryClient discoveryClient;
public ShareDTO findById(Integer id){
    //获取分享人详情
    Share share = this.shareMapper.selectByPrimaryKey(id);
    //发布人id
    Integer userId = share.getUserId();
    //怎么调用用户微服务的/user/{userId}??
    //用户中心所有实例的信息
    //List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
    //所有用户中心实例的请求地址
    /*List<String> targetURLS = instances.stream()
            .map(instance -> instance.getUri().toString() + "/users/{id}")
            .collect(Collectors.toList());
            //.findFirst()
            //当instances是空的列表时会抛出异常
            //.orElseThrow(() -> new IllegalArgumentException("当前没有实例"));*/
    //int i = ThreadLocalRandom.current().nextInt(targetURLS.size());
    //log.info("请求的目标地址:{} " + targetURLS.get(i));
    /*UserDTO userDTO = this.restTemplate.getForObject(
            "http://user-center/users/{userId}",
            UserDTO.class,userId
    );*/
    UserDTO userDTO = this.userCenterFeignClient.findById(userId);
    ShareDTO shareDTO = new ShareDTO();
    BeanUtils.copyProperties(share,shareDTO);
    shareDTO.setWxNickname(userDTO.getWxNickname());
    return shareDTO;

}

public static void main(String[] args) {
    RestTemplate restTemplate = new RestTemplate();
    //用Http的get方法去请求,并且返回一个对象
    String forObject =  restTemplate.getForObject(
            "http://localhost:8080/users/1",
            String.class
    );
    System.out.println(forObject);
}

public Share auditById(Integer id, ShareAuditDTO auditDTO) {
    //1.查询share是否存在,不存在或者当前的audit_status == NOT_YET,那么抛出异常
    Share share = this.shareMapper.selectByPrimaryKey(id);
    if(share == null){
        throw new IllegalSignatureException("参数非法!该分享不存在!");
    }
    if(!Objects.equals("NOT_YET",share.getAuditStatus())){
        throw new IllegalArgumentException("参数非法!该分享已审核通过或审核不通过!");
    }
    //
    if(AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())){
        //发送半消息
        String transactionId = UUID.randomUUID().toString();
        this.rocketMQTemplate.sendMessageInTransaction(
                "tx-add-bonus-group",
                "add-bonus",
                MessageBuilder
                .withPayload(
                        UserAddBonusMsgDTO.builder()
                        .userId(share.getUserId())
                        .bonus(50)
                        .build()
                )
                        //header也有妙用
                        .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                        .setHeader("share-id",id)
                .build(),
                auditDTO
        );
    }else{
        this.auditByIdInDB(id,auditDTO);
    }
    //2.审核资源,将状态设为PASS/REJECT
    /*share.setAuditStatus(auditDTO.getAuditStatusEnum().toString());
    this.shareMapper.updateByPrimaryKey(share);*/
    //3.如果是PASS,那么发消息给rocketmq,让用户中心去消费,并为发布人添加积分
    //异步执行 缩短整个接口的相应耗时,提升用户体验
    /*this.rocketMQTemplate.convertAndSend(
            "add-bonus",
            UserAddBonusMsgDTO.builder()
                .userId(share.getUserId())
                .bonus(50)
                .build()
    );*/
    //4. 把share写到缓存里面
    return share;
}
@Transactional(rollbackFor = Exception.class)
public void auditByIdInDB(Integer id,ShareAuditDTO auditDTO){
    Share share = Share.builder()
            .id(id)
            .auditStatus(auditDTO.getAuditStatusEnum().toString())
            .reason(auditDTO.getReason())
            .build();
    this.shareMapper.updateByPrimaryKeySelective(share);
    //4. 把share写到缓存里面
}
@Transactional(rollbackFor = Exception.class)
public void auditByIdWithRocketMqLog(Integer id,ShareAuditDTO auditDTO,String transactionId){
    this.auditByIdInDB(id,auditDTO);
    this.rocketmqTransactionLogMapper.insertSelective(
            RocketmqTransactionLog.builder()
            .transactionId(transactionId)
            .log("审核分享...")
            .build()
    );
}

}

正在回答

2回答

大目 2019-12-30 23:26:47

你的代码有好几处问题:

首先,项目使用的Spring Boot、Spring Cloud版本是不兼容的,你Spring Boot用的2.2.2,这个Boot版本必须Spring Cloud Hoxton才能兼容,详见《 4-2 版本与兼容性》;而目前Spring Cloud Alibaba最新的2.1.1只能兼容到Spring Cloud Greenwich。所以你的Spring Boot必须用2.1.x。(当然就目前来看,你还没有踩到坑),不过还是建议你改一下。

第二,你粗心了:com.itmuch.contentcenter.service.content.ShareService#auditById 这个方法里面,第108行

.withPayload(
       UserAddBonusMsgDTO.builder()
       .userId(share.getUserId())
       .bonus(50)
       .build()
)
       //header也有妙用
       .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
       .setHeader("share-id",id)

里面设置的header是share-id;

而com.itmuch.contentcenter.rocketmq.AddBonusTransactionListener#executeLocalTransaction里面,第29行

MessageHeaders headers = message.getHeaders();
String transactionId = (String)headers.get(RocketMQHeaders.TRANSACTION_ID);
Integer shareId = Integer.valueOf((String)headers.get("share_id"));
try{
   this.shareService.auditByIdWithRocketMqLog(shareId,(ShareAuditDTO)o,transactionId);
   return RocketMQLocalTransactionState.COMMIT;
}catch (Exception e){
   return RocketMQLocalTransactionState.ROLLBACK;
}

你get的header是share_id。

于是,在第29行,就会报空指针异常!!!!解决方案很简单:统一改成share-id或者share_id。这种问题其实很好解决,在第27行打个断点,逐行调试一下就知道了。


第三,多嘴一下,你代码里面有好几处用到了com.sun.xxx的包。sun包是比较特殊的包,一般是要杜绝使用的,具体原因可以百度下。以后编码注意一下。


我把我改好的代码上传到百度盘了。地址详见:https://pan.baidu.com/s/1U8nLGXsa9FvWpUWL9S79gg




1 回复 有任何疑惑可以回复我~
大目 2019-12-29 18:51:49

代码上传到GitHub或者Gitee,或者压缩上传到百度盘都可以。

我需要完整的代码,只有1个类我也不知道问题在哪里。


0 回复 有任何疑惑可以回复我~
  • 提问者 wenjuhe #1
    https://pan.baidu.com/s/1_FbFua_vbzA49-1H8qdkBw
    老师,这两个项目都上传完了,谢谢老师了
    回复 有任何疑惑可以回复我~ 2019-12-29 19:24:59
问题已解决,确定采纳
还有疑问,暂不采纳
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号