精华内容
下载资源
问答
  • 2019-09-12 04:43:50

    一、Java Date类型的时差问题

    请看下边这段代码

    public static void main(String[] args) throws Exception {
        Date date1 = new Date();
        System.out.println("date1: " + date1.toString());
        Date date2 = new Date(date1.toString());
        System.out.println("date2: " + date2.toString());
    }

    执行结果如下

    date1: Mon Jul 22 08:47:19 CST 2019
    date2: Mon Jul 22 22:47:19 CST 2019

    当前时间是2019年7月22日8点48分,CST是中国的时区China Standard Time的简称,但是可以看到date2的输入比实际时间多了14个小时。

    CTS代表的时区其实有四个(Central Standard Time (USA) UT-6:00、Central Standard Time (Australia) UT+9:30、China Standard Time UT+8:00、Cuba Standard Time UT-4:00),同时表示美国,澳大利亚,中国,古巴四个国家的标准时间。

    原因

    new Date(date1.toString())

    这个方法会调用Date.parse(String)方法,它传的参数是Mon Jul 22 08:47:19 CST 2019,这个方法上有一段注释

    * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
    *     ignoring case, is recognized as referring to the time zone in
    *     North America that is five, six, seven, or eight hours west of
    *     Greenwich, respectively. Any word that matches <tt>EDT, CDT,
    *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
    *     referring to the same time zone, respectively, during daylight
    *     saving time.</ul><p>

    可以看到CST会被当作美国中部的时区Central Standard Time,即JVM认为你传入的时间是美国中部的时间,而当date2调用toString方法的时候,它会检测到系统的时区是中国,就会自动加14个小时(东八区与西六区的时差),就变成了Mon Jul 22 22:47:19 CST 2019

    解决方法

    这个问题其实如果自己写代码的话很难出现,因为所有的Java书籍都不会这么教,大多数都是通过SimpleDateFormat,进行Date和String的转换,毕竟new Date(date1.toString())这个方法已经标注为废弃了

    二、Feign客户端的问题

    Feign客户端在进行通信时,会调用Date的toString方法转为String类型,服务端在接受的时候,使用的就是new Date(String)这个方法,这里就会发生前边介绍的问题,产生14个小时的时差

    解决方法

    在客户端添加代码,规定Feign在将Date参数转化成String参数的格式:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.openfeign.FeignFormatterRegistrar;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.format.FormatterRegistry;
    import org.springframework.stereotype.Component;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    @Slf4j
    @Component
    public class FeignDateFormatRegister implements FeignFormatterRegistrar {
    
        @Override
        public void registerFormatters(FormatterRegistry registry) {
            registry.addConverter(Date.class, String.class, new Date2StringConverter());
        }
    
        private class Date2StringConverter implements Converter<Date, String> {
            @Override
            public String convert(Date source) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.format(source);
            }
    
        }
    }

    在服务端添加代码,规定SpringContext在String和Date时的用的转化器,让转化器知道我们在客户端配置的参数格式:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.core.convert.support.GenericConversionService;
    import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
    
    import javax.annotation.PostConstruct;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    @Slf4j
    @Configuration
    public class FeignConfiguration {
    
        @Autowired
        private RequestMappingHandlerAdapter handlerAdapter;
    
        /**
         *  增加字符串转日期的功能       
         */
        @PostConstruct
        public void initEditableValidation() {
            ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter.getWebBindingInitializer();
            if (initializer.getConversionService() != null) {
                GenericConversionService genericConversionService = (GenericConversionService) initializer.getConversionService();
                genericConversionService.addConverter(String.class, Date.class, new String2DateConverter());
            }
        }
    
        class String2DateConverter implements Converter<String, Date> {
            @Override
            public Date convert(String source) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    return simpleDateFormat.parse(source);
                } catch (ParseException e) {
                    log.error("", e);
                }
                return null;
            }
        }
    }

    注意以上两个配置类需要自己配置包扫描之类的把它们加到Spring环境中

     

    参考资料:

    SpringCloud Feign 传输Date类型参数的时差问题

    Java Date数据类型时差问题

    转载于:https://my.oschina.net/icebergxty/blog/3077239

    更多相关内容
  • SpringCloudFeign讲解

    2021-12-06 17:04:03
    一、什么是Feign Feign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。  Spring Cloud的声明式调用, 可以做到...

     源码地址:https://gitee.com/datadogapache/dashboard/projects

    一、什么是Feign

        Feign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。
     Spring Cloud的声明式调用, 可以做到使用 HTTP请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。Feign的应用,让Spring Cloud微服务调用像Dubbo一样,Application Client直接通过接口方法调用Application Service,而不需要通过常规的RestTemplate构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

    二、Feign工作原理

        

    1、 启动类添加@EnableFeignClients注解,Spring会扫描标记了@FeignClient注解的接口,并生成此接口的代理对象

    2、 @FeignClient(value = "XC_SERVICE_MANAGE_CMS")即指定了cms的服务名称,Feign会从注册中心获取cms服务列表,并通过负载均衡算法进行服务调用。

    3、在接口方法中使用注解@GetMapping("/cms/page/get/{id}"),指定调用的url,Feign将根据url进行远程调用。

    • 主程序入口添加了@EnableFeignClients注解开启对FeignClient扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClient注解。

    • 当程序启动时,回进行包扫描,扫描所有@FeignClients的注解的类,并且讲这些信息注入Spring IOC容器中,当定义的的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate.当生成代理时,Feign会为每个接口方法创建一个RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象可封装HTTP请求需要的全部信息,如请求参数名,请求方法等信息都是在这个过程中确定的。

    • 然后RequestTemplate生成Request,然后把Request交给Client去处理,这里指的时Client可以时JDK原生的URLConnection,Apache的HttpClient,也可以时OKhttp,最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡进行微服务之间的调用。

    三、@FeignClient解析

    @FeignClient注解主要被@Target({ElementType.TYPE})修饰,表示该注解主要使用在接口上。它具备了如下的属性:

    • name:指定FeignClient的名称,如果使用了Ribbon,name就作为微服务的名称,用于服务发现。

    • url:url一般用于调试,可以指定@FeignClient调用的地址。

    • decode404: 当发生404错误时,如果该字段为true,会调用decoder进行解码,否则抛出FeignException.

    • configuration:Feign配置类,可以自定或者配置Feign的Encoder,Decoder,LogLevel,Contract。

    • fallback:定义容错的处理类,当调用远程接口失败或者超时时,会调用对应的接口的容错逻辑,fallback指定的类必须实现@Feign标记的接口。

    • fallbacjFactory:工厂类,用于生成fallback类实例,通过这个属性可以实现每个接口通用的容错逻辑们介绍重复的代码。

    • path:定义当前FeignClient的统一前缀。

    四、建立一个生产者和消费者

       1、建立生产者

          

    package com.example.springcloudfeign.Controller;
    
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    
    @RestController
    @CrossOrigin
    public class ProducerController {
        @RequestMapping("123")
        String Producer(){
            return "hello,welcome to connect me!";
        }
    }
    

    2、建立消费者

    package com.example.springcloudfeign.Server;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @FeignClient(value = "user")
    public interface Consumer {
        @RequestMapping("/123")
        String test();
    }

    3、配置微服务以及微服务的调用接口

    package com.example.springcloudfeign.Controller;
    
    import com.example.springcloudfeign.Server.Consumer;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @CrossOrigin
    public class ConsumerController {
        @Autowired
        Consumer consumer;
        @RequestMapping("789")
        String consumerTest(){
            return consumer.test();
        }
    }
    

    4、启动类添加@EnableDiscoveryClient 开启Nacos,添加@EnableFeignClients开启Fegin客户端,注入SpringIoc容器

    package com.example.springcloudfeign;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.cloud.openfeign.FeignClient;
    
    @EnableDiscoveryClient
    @EnableFeignClients
    @SpringBootApplication
    
    public class SpringcloudfeignApplication {
    
        public static void main(String[] args)
        {
            SpringApplication.run(SpringcloudfeignApplication.class, args);
        }
    
    }
    

    五、测试调用

    浏览器输入http://localhost:8090/789,其中消费者端口为8090,生产者端口为8089,访问消费者接口,可调用生产者的方法输出结果。

    单独调用消费者接口输出结果如下

     可见调用生产者和消费者的输出结果一致,也就验证了调用消费者接口时实际是调用生产者接口。

    展开全文
  • SpringCloudFeign请求拦截器说明 周所周知,feign在调用微服务系统中的某一服务时是无法携带前端请求后台时所带来的请求头信息的,例如token,这对于使用token验证的系统来说是很致命的;还有一种情况就是说当你使用...

    SpringCloudFeign请求拦截器说明

    周所周知,feign在调用微服务系统中的某一服务时是无法携带前端请求后台时所带来的请求头信息的,例如token,这对于使用token验证的系统来说是很致命的;还有一种情况就是说当你使用Spring拦截器作为验证权限的方式时,需要区分请求是从系统外部发送来的还是系统内部发送来的,这个校验也可以使用请求头信息解决。下面先为大家展示一下Feign拦截器

    import java.util.Enumeration;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import feign.RequestInterceptor;
    import feign.RequestTemplate;
    /**
     * Feign请求拦截器
     * 为Feign访问其他服务时加上请求头
     * @author a2417
     *
     */
    @Component
    public class FeignRequestConfig implements RequestInterceptor{
    	
    	public void apply(RequestTemplate requestTemplate) {
    		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    		if(attributes==null){
    			System.out.println("空针");
    		}
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                while (headerNames.hasMoreElements()) {
                    String name = headerNames.nextElement();
                    //获取前端传递的头信息
                    String values = request.getHeader("xtoken");
                    //添加头信息
                    requestTemplate.header("xtoken", values);
                    //添加自定义头信息
                    requestTemplate.header("fegin", "2190268123asd");
                }
                
            }
    		
    	}
    
    }
    
    

    下面解释一下这里面的关键内容:
    1. 这里有一个坑,可以看到我的代码中写入了一个判断空针的方法,这里需要说明的是,配置文件的加载优先级比较高,很可能会出现attributes为空的情况,解决办法可以是在启动类中加入以下代码,用以监听:

    /**
         * 监听器:监听HTTP请求事件
         * 解决RequestContextHolder.getRequestAttributes()空指针问题
         * @return
         */
        @Bean
        public RequestContextListener requestContextListener(){
            return new RequestContextListener();
        }
    

    2. 给该类加上一个@Component注解即可使全局Feign请求经过此拦截器,这里说一下为什么不用@Configuration注解的原因,因为@Configuration注解的优先级要高,这和我们上面说的问题有一定关连,@Configuration注解是已配置文件的编译方法启动的,里面的方法还需要加上@Bean注解,这样的优先级会使里面的attributes对象获取不到,如何真的想用@Configuration的话,可以将拦截器代码提出来做成一个对象,然后写一个@Configuration的类和一个带@bean的方法,里面返回提出来的对象即可!
    3. 如果只有某个feign调用则可以这样设置(但配置类不能在扫描目录下):

    @FeignClient(name = "organ",path = "/organ/OrganInfo",configuration = FeignSupportConfig.class)
    

    这样就不能使用我上面说的方法了,只能把拦截器提出来封装一个对象!

    展开全文
  • 该实例主要是提供给大家一个实例,告诉大家在实际的项目中使用SpringCloudFeign完成A服务调用B服务的实现步骤,不涉及原理讲解.

    前言

    该实例主要是提供给大家一个实例,告诉大家在实际的项目中使用SpringCloudFeign完成A服务调用B服务的实现步骤,不涉及原理讲解.


    整体描述

    mis-coursedesign服务调用mis-baseinfo服务的controller方法


    实现目的:

    mis-coursedesign服务中根据课程设计id获取课程设计信息,并从中提取负责教师id,远程调用mis-baseinfo服务:根据教师id查询教师详情信息.


    实现步骤

    💡 首先我们需要先在想要调用其他服务的服务中开启FeignClients服务,并创建相关的feign接口函数.

    1、在mis-coursedesign中建立feign包,在包中新建BaseInfoFeignService接口

    @FeignClient("mis-baseinfo")
    public interface BaseInfoFeignService {
    		// 负责教师详情信息
        @RequestMapping("/baseinfo/teacher/courseheadteacherinfo/{id}")
        public R courseHeadTeacherInfo(@PathVariable("id") Long id);
    }
    

    2、在MisCoursedesignApplication中添加@EnableFeignClients(basePackages = "com.hust.mis.coursedesign.feign")


    💡 下面我们需要在mis-baseinfo服务中实现BaseInfoService接口的方法

    3、 在实现开始前,我们需要先构造一个数据传输对象TeacherTo,该对象在mis-baseinfomis-coursedesign中都会用到,因此我们在mis-common中新建一个to包,在其中新建TeacherTo类,类中的属性为需要传输的字段.

    @Data
    public class TeacherTo {
        private Long id;
        private String collegeName;
        private String departmentName;
        private String labName;
        private String teacherName;
        private String registeredName;
        private Integer identityType;
        private String jobTitle;
        private String email
        private String tellphone;
        private String cellphone;
        private String workplace;
        private String researchFields;
    }
    

    4、 首先在mis-baseinfo中的TeacherController方法添加courseHeadTeacherInfo方法

    @RequestMapping("/courseheadteacherinfo/{id}")
    public R courseHeadTeacherInfo(@PathVariable("id") Long id){
        TeacherTo teacherTo = teacherService.courseHeadTeacherInfo(id);
        return R.ok().put("courseHeadTeacherInfo", teacherTo);
    }
    

    5、在TeacherService接口中声明courseHeadTeacherInfo方法

    TeacherTo courseHeadTeacherInfo(Long id);
    

    6、在TeacherServiceImpl中实现courseHeadTeacherInfo方法

    /**
     * 根据负责教师id返回负责教师详情信息
     * @param id
     * @return
     */
    @Override
    public TeacherTo courseHeadTeacherInfo(Long id) {
        TeacherEntity teacherEntity = this.baseMapper.selectById(id);
        TeacherTo teacherTo = new TeacherTo();
        BeanUtils.copyProperties(teacherEntity, teacherTo);
        return teacherTo;
    }
    

    💡 接下来,我们需要在mis-coursedesign中调用BaseInfoService中的方法用以实现目标功能

    7、在CourseDesignController中添加courseHeadTeacherInfoByCourseDesignId方法

    @RequestMapping("/courseheadteacherinfo/{id}")
    public R courseHeadTeacherInfoByCourseDesignId(@PathVariable("id") Long id){
        R r = courseDesignService.courseHeadTeacherInfo(id);
    
        return R.ok().put("courseHeadTeacherInfo",r.get("courseHeadTeacherInfo"));
    }
    

    8、在CourseDesignService接口中添加courseHeadTeacherInfo方法

    /**
     * 根据课程设计id返回负责教师详情信息
     * @param id
     * @return
     */
    @Override
    public R courseHeadTeacherInfo(Long id) {
        CourseDesignEntity courseDesignEntity = this.baseMapper.selectById(id);
        Long courseDesignHeadTeacherId = courseDesignEntity.getCourseDesignHeadTeacherId();
        R r = baseInfoFeignService.courseHeadTeacherInfo(courseDesignHeadTeacherId);
        return r;
    }
    

    💡 使用postman进行测试

    在这里插入图片描述在这里插入图片描述

    展开全文
  • 文章目录前言一、Feign和OpenFeign二、使用Feign调用get请求失败1.问题2.解决方案3.参考总结 前言 这是前言 参考链接: 一、Feign和OpenFeign  第一段 第二段 1.xxx:  内容关键字,内容。 2.xxx:  内容...
  • SpringCloudFeign底层是通过http/https协议进行通信,默认是采用java.net.HttpURLConnection,每次请求都会建立、关闭连接,为了性能考虑,可以引入httpclient、okhttp作为底层的通信框架。 maven坐标如下: <...
  • 微服务的访问可使用restTemplate,也可以使用feign远程调用,feign默认使用ribbon实现负载均衡 声明式的伪Http客户端,整合了feign和Hystrix,big和eureka结合,可实现负载均衡和断路器等功能 自动装配...
  • 在微服务架构中,我们不可避免的要使用到Feign去请求其他接口,这时就会有一个问题,如果Feign请求的接口需要返回一个对象,这个对象是其他微服务中的class,但是本服务中没有,接收时一般就只能将另一个微服务中的...
  • SpringCloudFeign原理剖析

    2021-03-06 00:34:03
    Feign是什么?简单来说,feign是用在微服务中,各个微服务间的调用。它是通过声明式的方式来定义接口,而不用实现接口。接口的实现由它通过spring bean的动态注册来实现的。fei...
  • 文章目录SpringCloudFeign多文件上传Feign多文件上传POM依赖Fiegn接口端配置类Feign接口接口提供端接口消费端在代码中调用Feign多文件上传,上面代码不需要改变消费方代码 SpringCloudFeign多文件上传 Feign多文件...
  • springCloudFeign使用示例

    2020-05-03 10:58:44
    框架版本 <spring-boot.version>1.5.15.RELEASE</spring-boot.version> <spring-cloud.version>Edgware.SR4</spring-cloud.version>...--feign--> <dependency> <...
  • SpringCloudFeign 全局异常处理

    千次阅读 2020-03-21 18:21:59
    服务端中,使用了全局拦截异常统一处理(@RestControllerAdvice),返回统一格式信息,导致feign客户端调用服务端时候,当服务端出现异常,客户端捕获不到异常,也未能进入熔断,降级 @Slf4j @RestControllerAdvice ...
  • Feign 接收DTO 在实现接口类,过不去,报Required request body is missing,困扰我18个小时 问题描述: 使用postman 发送json 格式数据,【content-type 设置 application/json】,json数据有多层嵌套。 前端...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,550
精华内容 1,420
关键字:

springcloudfeign

spring 订阅