服务间调用Feign + Hystrix

前言

提示:既然用到了微服务就会有服务间调用的问题产生,我总结了通过feign和hystrix进行调用的方式,希望对大家有所帮助。


提示:以下是本篇文章正文内容,下面案例可供参考

介绍

服务提供者是sms短信发送服务,服务消费者是系统用户模块;

1. 服务提供者

1.1 jar包引入

<dependencies>
		<!-- SpringCloud Openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
		<!-- SpringBoot Web -->
	    <dependency>
	      <groupId>org.springframework.boot</groupId>
	      <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
        <!-- SpringCloud Ailibaba Nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--阿里大于-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
        </dependency>
        <!--阿里大于-->
</dependencies>

1.2 配置文件

server.port=9300
spring.application.name=sms
# 注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 允许熔断机制
feign.hystrix.enabled=true
#消息:
sms.accessKeyId=
sms.accessKeySecret=

1.3 controller

/**
 * 短息服务
 *
 * @author lixy
 */
@RestController
@RequestMapping("/sms")
public class SmsController extends BaseController {

    @Autowired
    private SmsService smsService;

    @PostMapping("/send")
    public R<Map<String, String>> sendSms(@RequestParam("phoneNumbers") String phoneNumbers, @RequestParam("signName") String signName, @RequestParam("templateCode") String templateCode, @RequestParam("param") String param) {
        Map<String, String> map = smsService.sendSms(phoneNumbers, signName, templateCode, param);
        return R.ok(map);
    }
}
/**
 * 文件服务
 * @author lixy
 */
@RestController
@RequestMapping("/files")
public class FileController extends BaseController {

    @Autowired
    private IFileService fileService;

    /**
     * produces = MediaType.MULTIPART_FORM_DATA_VALUE
     * 加这个返回结果会报错: R<?>将...Content-type set null</>
     * 单一文件上传接口,上传失败由统一异常处理返回
     * @param file
     * @return
     */
    @PostMapping(value = "/uploadFile")
    public R<?> fileUpload(HttpServletRequest request, @RequestPart("file") MultipartFile file){
        if(file.isEmpty()){
            return R.fail("请选择文件!");
        }
        SysFile uploadFile = fileService.uploadFile(file, request);
        return R.ok(uploadFile, "文件上传成功!");
    }

    @PostMapping("/uploadFiles")
    public R<?> filesUpload(HttpServletRequest request, @RequestPart("files")MultipartFile[] files){
        if(files.length <=0 ){
            return R.fail("请选择文件!");
        }
        List<SysFile> filesPath = fileService.uploadFiles(files, request);
        return R.ok(filesPath, "文件上传成功!");
    }

    @GetMapping("/download")
    public void fileDownload(HttpServletResponse response,
                             @RequestParam(value = "filePath", required = false) String filePath,
                             @RequestParam(value = "fileName", required = false) String fileName,
                             @RequestParam(value = "isOnline", required = false, defaultValue = "false") Boolean isOnline){
        fileService.downloadFile(response, filePath, fileName , isOnline);
    }

}

1.4 service

public interface SmsService {

    Map<String,String> sendSms(String phoneNumbers, String signName, String templateCode, String param);
}

public interface IFileService {
    SysFile uploadFile(MultipartFile file, HttpServletRequest request);

    List<SysFile> uploadFiles(MultipartFile[] files, HttpServletRequest request);

    void downloadFile(HttpServletResponse response, String filePath, String fileName, Boolean isOnline);

}

1.5 impl

/**
 * @author lixy
 */
@Service
public class SmsServiceImpl implements SmsService {

    private final Logger logger = LoggerFactory.getLogger(SmsServiceImpl.class);

    @Autowired
    private SmsUtil smsUtil;

    public Map<String,String> sendSms(String phoneNumbers, String signName, String templateCode, String param){
        //调用发送短息的方法 ;
        try {
            SendSmsResponse response = smsUtil.sendSms(phoneNumbers, signName, templateCode, param);
            //封装返回值给map
            Map<String ,String> resultMap = new HashMap<String ,String>();
            resultMap.put("Code",response.getCode());
            resultMap.put("Message",response.getMessage());
            resultMap.put("RequestId",response.getRequestId());
            resultMap.put("BizId",response.getBizId());

            return resultMap;
        } catch (ClientException e) {
            logger.error("短信发送失败:{}" , e.getMessage());
            throw new CustomException("短信发送失败:" + e.getErrMsg());
        }
    }

}
/**
 * @author lixy
 */
@Service
@Primary
public class FastDFSFileServiceImpl implements IFileService {

    @Autowired
    private FastdfsClientService fastdfsClientService;
    @Value("${fastdfs.access-path}")
    private StringBuffer accessPath;
    @Value("${weaponry.manual_path}")
    private String manualPath;

    @Override
    public SysFile uploadFile(MultipartFile file, HttpServletRequest request) {
        String filename = file.getOriginalFilename();
        String extName = getFileExtName(filename);
        String[] strings;
        try {
            long start = System.currentTimeMillis();
            strings = fastdfsClientService.autoUpload(file.getBytes(), extName);
            long end = System.currentTimeMillis();
        } catch (Exception e) {
            throw new CustomException("文件上传失败!", e);
        }
//        accessPath + strings[0] + "/" + strings[1] + "==" + file.getSize() + "==上传耗时:"
        return new SysFile(filename, accessPath + strings[0] + "/" + strings[1]);
    }

    private String getFileExtName(String filename) {
        return filename.substring(filename.lastIndexOf(".") + 1);
    }

    @Override
    public List<SysFile> uploadFiles(MultipartFile[] files, HttpServletRequest request) {

        return null;
    }

    @Override
    public void downloadFile(HttpServletResponse response, String filePath, String fileName, Boolean isOnline) {
        try {
            if (StringUtils.isEmpty(filePath)) {
                // 默认下载使用手册 "典型目标知识图谱服务系统使用手册.pdf"
                filePath = manualPath;
                fileName = new String("典型目标知识图谱服务系统使用手册.pdf".getBytes(StandardCharsets.UTF_8), "ISO8859-1");
            } else {
                if(StringUtils.isEmpty(fileName)){
                    fileName = new String(filePath.substring(filePath.lastIndexOf("/") + 1).getBytes(StandardCharsets.UTF_8), "ISO8859-1");
                }else {
                    fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
                }
            }


            // http://192.168.1.138/group1/M00/00/00/wKgBvWBQY_OAaRBKAAIIxvji4o8112.pdf
            String[] strings = filePath.substring(accessPath.length()).split("/", 2);

            response.reset(); // 非常重要
            response.setContentType("application/force-download");// 设置强制下载不打开
            response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
            byte[] bytes = fastdfsClientService.download(strings[0], strings[1]);
            // 写出到指定文件
//            File file = new File("d:/测试.pdf");
//            FileOutputStream fileOutputStream = new FileOutputStream(file);
//            fileOutputStream.write(bytes);
//            fileOutputStream.close();
            // TODO 测试几个G的图片会不会溢出/报错 会
//            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length);
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(bytes);
            outputStream.close();
        } catch (Exception e) {
            throw new CustomException("文件下载失败!", e);
        }
    }
    
}

1.5 SmsUtil

@Component
public class SmsUtil {

    //产品名称:云通信短信API产品,开发者无需替换
    static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    static final String domain = "dysmsapi.aliyuncs.com";
    //加载properties中的key
    @Value("${sms.accessKeyId}")
    private String accessKeyId ;
    @Value("${sms.accessKeySecret}")
    private String accessKeySecret;

    public SendSmsResponse sendSms(String phoneNumbers,String signName,String templateCode,String param) throws ClientException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(phoneNumbers);
        //必填:短信签名-可在短信控制台中找到
        request.setSignName(signName);
        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(templateCode);
        //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
        request.setTemplateParam(param);

        //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");

        //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        request.setOutId("yourOutId");

        //hint 此处可能会抛出异常,注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

        return sendSmsResponse;
    }


    public QuerySendDetailsResponse querySendDetails(String bizId,String phoneNumber) throws ClientException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象
        QuerySendDetailsRequest request = new QuerySendDetailsRequest();
        //必填-号码
        request.setPhoneNumber(phoneNumber);
        //可选-流水号
        request.setBizId(bizId);
        //必填-发送日期 支持30天内记录查询,格式yyyyMMdd
        SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
        request.setSendDate(ft.format(new Date()));
        //必填-页大小
        request.setPageSize(10L);
        //必填-当前页码从1开始计数
        request.setCurrentPage(1L);

        //hint 此处可能会抛出异常,注意catch
        QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);

        return querySendDetailsResponse;
    }
}

1.6 启动类

/**
 * @author lixy
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
public class SmsApplication {
    public static void main(String[] args) {
        SpringApplication.run(SmsApplication.class);
    }
}

在这里插入图片描述

2. api(Feign+Hystrix熔断降级接口)

在这里插入图片描述

2.1 service接口

/**
 * Feign调用远程
 *  ServiceNameConstants.SMS_SERVICE = "sms",短信服务名
 */
@FeignClient(contextId = "remoteSmsService", value = ServiceNameConstants.SMS_SERVICE, fallbackFactory = RemoteSmsServiceFactory.class)
public interface RemoteSmsService {
	// 一定要加@RequestParam 否则调用时候会报错: 参数太长
    @PostMapping("/sms/send")
    public R<Map<String, String>> sendSms(@RequestParam("phoneNumbers") String phoneNumbers, @RequestParam("signName") String signName, @RequestParam("templateCode") String templateCode, @RequestParam("param") String param);
}

/**
 * 文件服务
 *
 * @author guanwei
 */
@FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
@RequestMapping("/files")
public interface RemoteFileService {

    /**
     * 单一文件上传接口,上传失败由统一异常处理返回
     * @param file
     * @return
     */
    @PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<SysFile>  fileUpload( HttpServletRequest request, @RequestPart("file") MultipartFile file);

    /**
     * 批量上传
     * @param request
     * @param files
     * @return
     */
    @PostMapping("/uploadFiles", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<List<SysFile>> filesUpload( HttpServletRequest request, @RequestPart("files")MultipartFile[] files);

    /**
     * 下载及预览
     * @param response
     * @param filePath
     * @param fileName
     * @param isOnline
     */
    @GetMapping("/download")
    public void fileDownload( HttpServletResponse response,
                             @RequestParam(value = "filePath", required = false) String filePath,
                             @RequestParam(value = "fileName", required = false) String fileName,
                             @RequestParam(value = "isOnline", required = false, defaultValue = "false") Boolean isOnline);
}

注: api中的上传文件接口需要加 consumes = MediaType.MULTIPART_FORM_DATA_VALUE

2.2 服务熔断降级

/**
 * 降级处理
 * @author lixy
 */
@Component
public class RemoteSmsServiceFactory implements FallbackFactory<RemoteSmsService> {
    private static final Logger log = LoggerFactory.getLogger(RemoteSmsServiceFactory.class);

    @Override
    public RemoteSmsService create(Throwable cause) {
        log.error("短信服务调用失败:{}", cause.getMessage());
        return new RemoteSmsService() {
            @Override
            public R<Map<String, String>> sendSms(String phoneNumbers, String signName, String templateCode, String param) {
                return R.fail("短信发送失败:" + cause.getMessage());
            }
        };
    }
}
/**
 * @author lixy
 */
@Component
public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService> {
    private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);

    @Override
    public RemoteFileService create(Throwable cause) {
        return new RemoteFileService() {
            @Override
            public R<SysFile> fileUpload(HttpServletRequest request, MultipartFile file) {
                log.error("服务调用失败:{}", cause.getMessage());
                return R.fail("上传文件失败:" + cause.getMessage());
            }

            @Override
            public R<List<SysFile>> filesUpload(HttpServletRequest request, MultipartFile[] files) {
                log.error("服务调用失败:{}", cause.getMessage());
                return R.fail("批量上传文件失败:" + cause.getMessage());
            }

            @Override
            public void fileDownload(HttpServletResponse response, String filePath, String fileName, Boolean isOnline) {
                log.error("服务调用失败:{}", cause.getMessage());
            }
        };
    }
}

2.3 将降级处理加载到spring容器

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.yan.sms.api.factory.RemoteSmsServiceFactory

2.4 domain

/**
 * @author lixy
 */
public class SysFile {
    /**
     * 文件名称
     */
    private String name;

    /**
     * 文件地址
     */
    private String url;

    public SysFile(){

    }
    public SysFile(String name, String url) {
        super();
        this.name = name;
        this.url = url;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                .append("name", getName())
                .append("url", getUrl())
                .toString();
    }
}

3.服务消费者

3.1 jar包引入

    <!-- SpringBoot Web -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- SpringCloud Openfeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
	<!-- SpringCloud Ailibaba Nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--atlas-sms-api-->
    <dependency>
        <groupId>com.yan</groupId>
        <artifactId>atlas-sms-api</artifactId>
    </dependency>

3.2 配置文件

# 注册地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 开启熔断
feign.hystrix.enabled=true

3.3 服务启动类

/**
 * 系统应用启动项
 * author: lixy
 */
@SpringBootApplication
@MapperScan("com.guanwei.atlas.system.mapper")
@EnableFeignClients(basePackages = {"com.yan.sms.api"}) //解决消费者找不到feign接口
@EnableDiscoveryClient      // 注册到nacos,使其他服务发现
@EnableCircuitBreaker       // 熔断
public class AtlasSystemApplicaiton {
    public static void main(String[] args) {
        SpringApplication.run(AtlasSystemApplicaiton.class);
    }
}

@EnableDiscoveryClient // 注册到nacos,使其他服务发现
@EnableCircuitBreaker // 熔断
@SpringBootApplication
这三个可以用
@SpringCloudApplication代替

3.4 SysUserController

    /**
     * 发送短信
     * @param phone
     * @return
     */
    @RequestMapping("/sendSmsCode")
    public R<?> sendSmsCode(String phone){
        sysUserService.sendSmsCode(phone);
        return R.ok(true,"短信发送成功");
    }

3.5 SysUserServiceImpl

   /**
 * 用户信息Service业务层处理
 *
 * @author lixy
 * @date 2021-01-06
 */
@Service
public class SysUserServiceImpl implements ISysUserService {
    @Autowired
    private RemoteSmsService smsService;
    @Value("岩")
    private String signName;
    @Value("SMS_16*******")
    private String templateCode;
    @Autowired
    private RedisTemplate redisTemplate;
    
    //发送短信的方法:需要httpClient发送url,就是调用阿里云发送短信;
    public void sendSmsCode(String phone) {
        //1.生成动态的6位验证码:
        int num = (int) (Math.random() + 1);
        String smsCode = num + RandomStringUtils.randomNumeric(5);//因为当第一个数字是0的时候阿里云默认去掉0;
        //2.将生成的验证码保存到redis中15分钟,
        redisTemplate.boundValueOps(phone).set(smsCode, 15L, TimeUnit.MINUTES);
        String param = "{\"code\":" + smsCode + "}";
        R<Map<String, String>> result = smsService.sendSms(phone, signName, templateCode, param);
        if(result.getCode() == 200){
            Map<String, String> response = result.getData();
            if (!response.get("Code").equals("200")) {
                throw new CustomException(result.getMsg());
            }
        }else{
            throw new CustomException(result.getMsg());
        }
    }
}

如果有其他消费者想调用sms,直接引入api的jar就好啦!!!

补充其他问题:

  1. 新入职某公司,然后接口返回值用的R这种返回类。发现某保存功能报错。
    根据debug发现,人员保存的时候会通过feign调用的人员服务。
    在这里插入图片描述
    在这里插入图片描述
    那么为什么会走服务降级呢?本身接口没有问题呀!这种情况可能有以下几个原因:
    1. 在feign调用接口的参数无@RequestParam注解、
    2. 返回值类型和接收的类型不一致。(这个问题就出现在这里)
    3. 没有包扫描。
      返回值类型是R,但是返回的时候调用了R.fail(“用户已存在!”)这个方法,这个方法的返回值类型不对。
      在这里插入图片描述
      在这里插入图片描述

package org.core.tool.api;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.core.tool.constant.LaConstant;
import org.core.tool.utils.ObjectUtil;
import org.springframework.lang.Nullable;

import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Optional;

/**
 * 统一API响应结果封装,这个封装的fail用到feign中会出现问题。导致只走服务降级。
 *
 */
@Getter
@Setter
@ToString
@ApiModel(description = "返回信息")
@NoArgsConstructor
public class R<T> implements Serializable {

	private static final long serialVersionUID = 1L;

	@ApiModelProperty(value = "状态码", required = true)
	private int code;
	@ApiModelProperty(value = "是否成功", required = true)
	private boolean success;
	@ApiModelProperty(value = "承载数据")
	private T data;
	@ApiModelProperty(value = "返回消息", required = true)
	private String msg;

	private R(IResultCode resultCode) {
		this(resultCode, null, resultCode.getMessage());
	}

	private R(IResultCode resultCode, String msg) {
		this(resultCode, null, msg);
	}

	private R(IResultCode resultCode, T data) {
		this(resultCode, data, resultCode.getMessage());
	}

	private R(IResultCode resultCode, T data, String msg) {
		this(resultCode.getCode(), data, msg);
	}

	private R(int code, T data, String msg) {
		this.code = code;
		this.data = data;
		this.msg = msg;
		this.success = ResultCode.SUCCESS.code == code;
	}

	/**
	 * 判断返回是否为成功
	 *
	 * @param result Result
	 * @return 是否成功
	 */
	public static boolean isSuccess(@Nullable R<?> result) {
		return Optional.ofNullable(result)
			.map(x -> ObjectUtil.nullSafeEquals(ResultCode.SUCCESS.code, x.code))
			.orElse(Boolean.FALSE);
	}

	/**
	 * 判断返回是否为成功
	 *
	 * @param result Result
	 * @return 是否成功
	 */
	public static boolean isNotSuccess(@Nullable R<?> result) {
		return !R.isSuccess(result);
	}

	/**
	 * 返回R
	 *
	 * @param data 数据
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> data(T data) {
		return data(data, LaConstant.DEFAULT_SUCCESS_MESSAGE);
	}

	/**
	 * 返回R
	 *
	 * @param data 数据
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> data(T data, String msg) {
		return data(HttpServletResponse.SC_OK, data, msg);
	}

	/**
	 * 返回R
	 *
	 * @param code 状态码
	 * @param data 数据
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> data(int code, T data, String msg) {
		return new R<>(code, data, data == null ? LaConstant.DEFAULT_NULL_MESSAGE : msg);
	}

	/**
	 * 返回R
	 *
	 * @param msg 消息
	 * @param <T> T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(String msg) {
		return new R<>(ResultCode.SUCCESS, msg);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(IResultCode resultCode) {
		return new R<>(resultCode);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param msg        消息
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(IResultCode resultCode, String msg) {
		return new R<>(resultCode, msg);
	}

	/**
	 * 返回R
	 *
	 * @param msg 消息
	 * @param <T> T 泛型标记
	 * @return R
	 */
	public static <T> R<T> fail(String msg) {
		return new R<>(ResultCode.FAILURE, msg);
	}


	/**
	 * 返回R
	 *
	 * @param code 状态码
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> fail(int code, String msg) {
		return new R<>(code, null, msg);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> fail(IResultCode resultCode) {
		return new R<>(resultCode);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param msg        消息
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> fail(IResultCode resultCode, String msg) {
		return new R<>(resultCode, msg);
	}

	/**
	 * 返回R
	 *
	 * @param flag 成功状态
	 * @return R
	 */
	public static <T> R<T> status(boolean flag) {
		return flag ? success(LaConstant.DEFAULT_SUCCESS_MESSAGE) : fail(LaConstant.DEFAULT_FAILURE_MESSAGE);
	}

}

新入职一家公司,然后本地启动system服务总是报错,No fallback instance of type class org.file.feign.IFileClientFallback found for org.file.feign client la-file。找了半天问题,前任大哥在IFileFeignClientFallback中的实现@Overrid 同时又加了@get @post,然后在接口那里也有。注释掉就好了。可能不是这个问题?
希望对大家有所帮助~~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值