当前位置: 首页 > news >正文

网站用ps如何做安阳县属于哪个省哪个市

网站用ps如何做,安阳县属于哪个省哪个市,php 网站下载器,深圳网站建设开发前言 如果你项目里还在用传统的编程式Http客户端比如HttpClient、Okhttp去直接对接第三方Http接口#xff0c; 那么你项目一定充斥着大量的对接逻辑和代码#xff0c; 并且针对不同的对接渠道方需要每次封装一次调用的简化#xff0c; 一旦封装不好系统将会变得难以维护 那么你项目一定充斥着大量的对接逻辑和代码 并且针对不同的对接渠道方需要每次封装一次调用的简化 一旦封装不好系统将会变得难以维护难以阅读 甚至不同的开发同学会用自己的方式用不同的Http客户端用不同的封装逻辑去对接接口 这种情况一般发生于项目换了维护者然后代码负责人也没把控代码质量和规范。 如果你的项目里也存在这样的问题那么UniHttp就是你的规范你的版本答案。 1、简介 一个声明式的Http接口对接框架能以极快的方式完成对一个第三方Http接口的对接和使用只要配置一下即可重复使用 不需要开发者去关注如何发送一个请求如何去传递Http请求参数以及如何对请求结果进行处理和反序列化这些框架都帮你一一实现 就像配置 Spring的Controller 那样简单只不过相当于是反向配置而已 该框架更注重于如何保持高内聚和可读性高的代码情况下与快速第三方渠道接口进行对接和集成而非像传统编程式的Http请求客户端比如HttpClient、Okhttp那样专注于如何去发送Http请求虽然底层也是用的Okhttp去发送请求。 与其说的是对接的Http接口不如说是对接的第三方渠道UniHttp可支持自定义接口渠道方HttpAPI注解以及一些自定义的对接和交互行为 为此扩展了发送和响应和反序列化一个Http请求的各种生命周期钩子开发者可自行去扩展实现。 2、快速开始 2.1、引入依赖 dependencygroupIdio.github.burukeyou/groupIdartifactIduniapi-http/artifactIdversion0.0.4/version/dependency2.2、对接接口 在类上标记HttpApi注解然后指定请求的域名url, 然后就可以为方法配发去对接哪个接口。 比如下面两个方法的配置则对接了 GET http://localhost:8080/getUser和 POST http://localhost:8080/addUser 两个接口 方法返回值定义成Http响应body对应的类型即可默认会使用fastjson反序列化Http响应body的值为该类型对象。 HttpApi(url http://localhost:8080) interface UserHttpApi {GetHttpInterface(/getUser)BaseRspString getUser(QueryPar(name) String param,HeaderPar(userId) Integer id);PostHttpInterface(/addUser)BaseRspAdd4DTO addUser(BodyJsonPar Add4DTO req);}QueryPar 表示将参数值放到Http请求的查询参数内 HeaderPar 表示将参数值放到Http请求的请求头里 BodyJsonPar 表示将参数值放到Http请求body内并且content-type是application/json 1、getUser方法最终构建的Http请求报文为 GET http://localhost:8080/getUser?nameparam Header:userId: id2、addUser最终构建的Http请求报文为 POST: http://localhost:8080/addUser Header: Content-Type: application/jsonBody:{id:1,name:jay}2.3、声明定义的HttpAPI的包扫描路径 在spring的配置类上使用UniAPIScan注解标记定义的HttpAPI的包扫描路径,会自动为标记了HttpApi接口生成代理对象并且注入到Spring容器中 之后只需要像使用Spring的其他bean一样依赖注入使用即可 UniAPIScan(com.xxx.demo.api) SpringBootApplication public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class,args);} }2.4 依赖注入使用即可 Service class UserAppService {Autowiredprivate UserHttpApi userHttpApi;public void doSomething(){userHttpApi.getUser(jay,3);} } 3、说明介绍 3.1、HttpApi注解 用于标记接口上该接口上的方法会被代理到对应的Http请求接口可指定请求的域名也可指定自定义的Http代理逻辑等等。 3.2、HttpInterface注解 用于配置一个接口的参数包括请求方式、请求路径、请求头、请求cookie、请求查询参数等等 并且内置了以下请求方式的HttpInterface不必再每次手动指定请求方式 PostHttpInterfacePutHttpInterfaceDeleteHttpInterfaceGetHttpInterface PostHttpInterface(// 请求路径path /getUser,// 请求头headers {clientType:sys-app,userId:99},// url查询参数 params {name周杰伦,age1},// url查询参数拼接字符串paramStr a1b2c3d哈哈e%E7%89%9B%E9%80%BC,// cookie 字符串cookie name1;sessionId999)BaseRspString getUser();3.3、Par注解 以下各种Par后缀的注解主要用于方法参数上用于指定在发送请求时将参数值放到Http请求体的哪部分上。 为了方便描述下文描述的普通值就是表示String基本类型、基本类型的包装类型等类型. 简单复习下Http协议报文 QueryPar注解 标记Http请求url的查询参数 支持以下方法参数类型的标记: 普通值、普通值集合、对象、Map PostHttpInterfaceBaseRspString getUser(QueryPar(id) String id, // 普通值 QueryPar(ids) ListInteger idsList, // 普通值集合QueryPar User user, // 对象QueryPar MapString,Object map); // Map 如果类型是普通值或者普通值集合需要手动指定参数名因为是当成单个查询参数传递 如果类型是对象或者Map是当成多个查询参数传递字段名或者map的key名就是参数名字段值或者map的value值就是参数值。 如果是对象参数名默认是字段名由于用的是fastjson序列化可以用JSONField指定别名 PathPar注解 标记Http请求路径变量参数仅支持标记普通值类型 PostHttpInterface(/getUser/{userId}/detail)BaseRspString getUser(PathPar(userId) String id); // 普通值HeaderPar注解 标记Http请求头参数 支持以下方法参数类型 对象、Map、普通值 PostHttpInterfaceBaseRspString getUser(HeaderPar(id) String id, // 普通值 HeaderPar User user, // 对象HeaderPar MapString,Object map); // Map 如果类型是普通值类型需要手动指定参数名当成单个请求头参数传递. 如果是对象或者Map当成多个请求头参数。 CookiePar注解 用于标记Http请求的cookie请求头 支持以下方法参数类型: Map、Cookie对象、字符串 PostHttpInterfaceBaseRspString getUser(CookiePar(id) String cookiePar, // 普通值 指定name当成单个cookie键值对处理CookiePar String cookieString, // 普通值 不指定name当成完整的cookie字符串处理CookiePar com.burukeyou.uniapi.http.support.Cookie cookieObj, // 单个Cookie对象 CookiePar Listcom.burukeyou.uniapi.http.support.Cookie cookieList // Cookie对象列表CookiePar MapString,Object map); // Map 如果类型是字符串时当指定参数名时当成单个cookie键值对处理如果不指定参数名时当成完整的cookie字符串处理比如a1;b2;c3 这样 如果是Map当成多个cookie键值对处理。 如果类型是内置的 com.burukeyou.uniapi.http.support.Cookie对象当成单个cookie键值对处理 BodyJsonPar注解 用于标记Http请求体内容为json形式: 对应content-type为 application/json 支持以下方法参数类型: 对象、对象集合、Map、普通值、普通值集合 PostHttpInterfaceBaseRspString getUser(BodyJsonPar String id, // 普通值BodyJsonPar String[] id // 普通值集合BodyJsonPar ListUser userList, // 对象集合BodyJsonPar User user, // 对象BodyJsonPar MapString,Object map); // Map序列化和反序列化默认用的是fastjson所以如果想指定别名可以在字段上标记 JSONField 注解取别名 BodyFormPar注解 用于标记Http请求体内容为普通表单形式: 对应content-type为 application/x-www-form-urlencoded 支持以下方法参数类型 对象、Map、普通值 PostHttpInterfaceBaseRspString getUser(BodyFormPar(name) String value, // 普通值BodyFormPar User user, // 对象BodyFormPar MapString,Object map); // Map如果类型是普通值类型需要手动指定参数名当成单个请求表单键值对传递 BodyMultiPartPar注解 用于标记Http请求体内容为复杂形式: 对应content-type为 multipart/form-data 支持以下方法参数类型: 对象、Map、普通值、File对象 PostHttpInterfaceBaseRspString getUser(BodyMultiPartPar(name) String value, // 单个表单文本值BodyMultiPartPar User user, // 对象BodyMultiPartPar MapString,Object map, // MapBodyMultiPartPar(userImg) File file); // 单个表单文件值如果参数类型是普通值或者File类型当成单个表单键值对处理需要手动指定参数名。 如果参数类型是对象或者Map当成多个表单键值对处理。 如果字段值或者map的value参数值是File类型则自动当成是文件表单字段传递处理 BodyBinaryPar注解 用于标记Http请求体内容为二进制形式: 对应content-type为 application/octet-stream 支持以下方法参数类型: InputStream、File、InputStreamSource PostHttpInterfaceBaseRspString getUser(BodyBinaryPar InputStream value, BodyBinaryPar File user, BodyBinaryPar InputStreamSource map); ComposePar注解 这个注解本身不是对Http请求内容的配置仅用于标记一个对象然后会对该对象内的所有标记了其他Par注解的字段进行嵌套解析处理 目的是减少方法参数数量支持都内聚到一起传递 支持以下方法参数类型: 对象 PostHttpInterfaceBaseRspString getUser(ComposePar UserReq req); 比如UserReq里面的字段可以嵌套标记其他Par注解具体支持的标记类型和处理逻辑与前面一致 class UserReq {QueryParprivate Long id;HeaderParprivate String name;BodyJsonParprivate Add4DTO req;CookieParprivate String cook; }3.4、原始的HttpResponse HttpResponse表示Http请求的原始响应对象如果业务需要关注拿到完整的Http响应只需要在方法返回值包装返回即可。 如下面所示此时HttpResponseAdd4DTO里的泛型Add4DTO才是代表接口实际返回的响应内容后续可直接手动获取 PostHttpInterface(/user-web/get)HttpResponseAdd4DTO get();通过它我们就可以拿到响应的Http状态码、响应头、响应cookie等等当然也可以拿到我们的响应body的内容通过getBodyResult方法 3.5、处理文件下载接口 对于若是下载文件的类型的接口可将方法返回值定义为 HttpBinaryResponse、HttpFileResponse、HttpInputStreamResponse 的任意一种 这样就可以拿到下载后的文件。 HttpBinaryResponse: 表示下载的文件内容以二进制形式返回如果是大文件请谨慎处理因为会存放在内存中 HttpFileResponse: 表示下载的文件内容以File对象返回这时文件已经被下载到了本地磁盘 HttpInputStreamResponse: 表示下载的文件内容输入流的形式返回这时文件其实还没被下载到客户端调用者可以自行读取该输入流进行文件的下载 3.6、HttpApiProcessor 生命周期钩子 HttpApiProcessor是一个Http请求接口的各种生命周期钩子开发者可以实现它在里面自定义编写各种对接逻辑。 然后可以配置到HttpApi注解或者HttpInterface注解上, 然后框架内部默认会从SpringContext获取获取不到则手动new一个。 通常一个Http请求需要经历 构建请求参数、发送Http请求时Http响应后获取响应内容、反序列化Http响应内容成具体对象。 目前提供了4种钩子,执行顺序流程如下: postBeforeHttpMetadata (请求发送前)在发送请求之前对Http请求体后置处理|VpostSendingHttpRequest (请求发送时)在Http请求发送时处理|VpostAfterHttpResponseBodyString (请求响应后)对响应body文本字符串进行后置处理|VpostAfterHttpResponseBodyResult (请求响应后)对响应body反序列化后的结果进行后置处理|VpostAfterMethodReturnValue (请求响应后)对代理的方法的返回值进行后置处理类似aop的后置处理. 1、postBeforeHttpMetadata: 可在发送http请求之前对请求体进行二次处理比如加签之类 2、postSendHttpRequest: Http请求发送时会回调该方法可以在该方法执行自定义的发送逻辑或者打印发送日志 3、postAfterHttpResponseBodyString Http请求响应后对响应body字符串进行进行后置处理比如如果是加密数据可以进行解密 4、postAfterHttpResponseBodyResult Http请求响应后对响应body反序列化后的对象进行后置处理比如填充默认返回值 5、postAfterMethodReturnValue Http请求响应后对代理的方法的返回值进行后置处理类似aop的后置处理 . 回调参数说明: HttpMetadata: 表示此次Http请求的请求体包含请求url请求头、请求方式、请求cookie、请求体、请求参数等等。 HttpApiMethodInvocation: 继承自MethodInvocation 表示被代理的方法调用上下文可以拿到被代理的类被代理的方法被代理的HttpAPI注解、HttpInterface注解等信息 3.7、配置自定义的Http客户端 默认使用的是Okhttp客户端如果要重新配置Okhttp客户端,注入spring的bean即可,如下 Configuration public class CusotmConfiguration {Beanpublic OkHttpClient myOHttpClient(){return new OkHttpClient.Builder().readTimeout(50, TimeUnit.SECONDS).writeTimeout(50, TimeUnit.SECONDS).connectTimeout(10, TimeUnit.SECONDS).connectionPool(new ConnectionPool(20,10, TimeUnit.MINUTES)).build();} } 4、企业级渠道对接实战 案例背景 假设现在需要对接一个某天气服务的所有接口需要在请求cookie带上一个token字段和sessionId字段 这两个字段的值需要每次接口调用前先手动调渠道方的一个特定的接口申请获取token值在该接口返回值中返回sessionId在该接口的响应头中返回。然后还需要在请求头上带上一个sign签名字段 该sign签名字段生成规则需要用渠道方提供的公钥对所有请求体和请求参数进行加签生成。 然后还需要在每个接口的查询参数上都带上一个渠道方分配的客户端appId。 4.1 在application.yml中配置对接渠道方的信息 channel:mtuan:# 请求域名url: http://127.0.0.1:8999# 分配的渠道appIdappId: UUU-asd-01# 分配的公钥publicKey: fajdkf9492304jklfahqq4.2 自定义该渠道方的HttpAPI注解 假设现在对接的是某团所以自定义注解叫MTuanHttpApi吧然后需要在该注解上标记HttpApi注解并且需要配置processor字段需要去自定义实现一个HttpApiProcessor这个具体实现后续讲。 有了这个注解后就可以自定义该注解与对接渠道方相关的各种字段配置当然也可以不定义。 注意这里url的字段是使用 AliasFor(annotation HttpApi.class) 这样构建的HttpMetadata中会默认解析填充要请求体不标记则也可自行处理。 Inherited Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) HttpApi(processor MTuanHttpApiProcessor.class) public interface MTuanHttpApi {/*** 渠道方域名地址*/AliasFor(annotation HttpApi.class)String url() default ${channel.mtuan.url};/*** 渠道方分配的appId*/String appId() default ${channel.mtuan.appId}; } Slf4j Component public class MTuanHttpApiProcessor implements HttpApiProcessorMTuanHttpApi {}注意实现的HttpApiProcessor泛型要指定为刚才定义的注解MTuanHttpApi类型因为这个HttpApiProcessor配置到它上面如果需要通用处理可以定义为Annocation类型 4.3 对接接口 有了MTuanHttpApi注解之后就可以开始对接接口了比如假设有两个接口要对接。一个就是前面说的获取令牌的接口。 一个是获取天气情况的接口。 为什么getToken方法返回值是 HttpResponse, 这是UniHttp内置的原始Http响应对象方便我们去拿到原始Http响应体的一些内容比如响应状态码、响应cookie。 其中的泛型BaseRsp才是实际的Http响应体反序列化后的内容。 而getCityWeather方法没有使用HttpResponse包装, BaseRsp只是单纯Http响应体反序列化后的内容这是两者的区别。 前面介绍过 HttpResponse其实大部份接口是不关注HttpResponse的可以不用去配置。 MTuanHttpApi public interface WeatherApi {/*** 根据城市名获取天气情况*/GetHttpInterface(/getCityByName)BaseRspWeatherDTO getCityWeather(QueryPar(city) String cityName);/*** 根据appId和公钥获取令牌*/PostHttpInterface(/getToken)HttpResponseBaseRspTokenDTO getToken(HeaderPar(appId) String appId, HeaderPar(publicKey)String publicKey);} 4.4、自定义HttpApiProcessor 在之前我们自定义了一个MTuanHttpApi注解上指定了一个MTuanHttpApiProcessor接下来我们去实现他的具体内容为了实现我们案例背景里描述的功能。 Slf4j Component public class MTuanHttpApiProcessor implements HttpApiProcessorMTuanHttpApi {/*** 渠道方分配的公钥*/Value(${channel.mtuan.publicKey})private String publicKey;Value(${channel.mtuan.appId})private String appId;Autowiredprivate Environment environment;Autowiredprivate WeatherApi weatherApi;/** 实现-postBeforeHttpMetadata 发送Http请求之前会回调该方法可对Http请求体的内容进行二次处理** param httpMetadata 原来的请求体* param methodInvocation 被代理的方法* return 新的请求体*/Overridepublic HttpMetadata postBeforeHttpMetadata(HttpMetadata httpMetadata, HttpApiMethodInvocationMTuanHttpApi methodInvocation) {/*** 在查询参数中添加提供的appId字段*/// 获取MTuanHttpApi注解MTuanHttpApi apiAnnotation methodInvocation.getProxyApiAnnotation();// 获取MTuanHttpApi注解的appId由于该appId是环境变量所以我们从environment中解析取出来String appIdVar apiAnnotation.appId();appIdVar environment.resolvePlaceholders(appIdVar);// 添加到查询参数中httpMetadata.putQueryParam(appId,appIdVar);/*** 生成签名sign字段*/// 获取所有查询参数MapString, Object queryParam httpMetadata.getHttpUrl().getQueryParam();// 获取请求体参数HttpBody body httpMetadata.getBody();// 生成签名String signKey createSignKey(queryParam,body);// 将签名添加到请求头中httpMetadata.putHeader(sign,signKey);return httpMetadata;}private String createSignKey(MapString, Object queryParam, HttpBody body) {// todo 伪代码// 1、将查询参数拼接成字符串String queryParamString queryParam.entrySet().stream().map(e - e.getKey() e.getValue()).collect(Collectors.joining(;));// 2、将请求体参数拼接成字符串String bodyString ;if (body instanceof HttpBodyJSON){// application/json 类型的请求体bodyString body.toStringBody();}else if (body instanceof HttpBodyFormData){// application/x-www-form-urlencoded 类型的请求体bodyString body.toStringBody();}else if (body instanceof HttpBodyMultipart){// multipart/form-data 类型的请求体bodyString body.toStringBody();}// 使用公钥publicKey 加密拼接起来String sign publicKey queryParamString bodyString;try {MessageDigest md MessageDigest.getInstance(SHA-256);byte[] digest md.digest(sign.getBytes());return new String(digest);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** 实现-postBeforeHttpMetadata 发送Http请求时可定义发送请求的行为 或者打印请求和响应日志。*/Overridepublic HttpResponse? postSendHttpRequest(HttpSender httpSender, HttpMetadata httpMetadata) {// 忽略 weatherApi.getToken的方法回调否则该方法也会回调此方法会递归死循环。 或者该接口指定自定义的HttpApiProcessor重写postSendingHttpRequestMethod getTokenMethod ReflectionUtils.findMethod(WeatherServiceApi.class, getToken,String.class,String.class);if (getTokenMethod null || getTokenMethod.equals(methodInvocation.getMethod())){return httpSender.sendHttpRequest(httpMetadata);}// 1、动态获取token和sessionIdHttpResponseString httpResponse weatherApi.getToken(appId, publicKey);// 从响应体获取令牌tokenString token httpResponse.getBodyResult();// 从响应头中获取sessionIdString sessionId httpResponse.getHeader(sessionId);// 把这两个值放到此次的请求cookie中httpMetadata.addCookie(new Cookie(token,token));httpMetadata.addCookie(new Cookie(sessionId,sessionId));log.info(开始发送Http请求 请求接口:{} 请求体:{},httpMetadata.getHttpUrl().toUrl(),httpMetadata.toHttpProtocol());// 使用框架内置工具实现发送请求HttpResponse? rsp httpSender.sendHttpRequest(httpMetadata);log.info(开始发送Http请求 响应结果:{},rsp.toHttpProtocol());return rsp;}/*** 实现-postAfterHttpResponseBodyResult 反序列化后Http响应体的内容后回调可对该结果进行二次处理返回* param bodyResult Http响应体反序列化后的结果* param rsp 原始Http响应对象* param method 被代理的方法* param httpMetadata Http请求体*/Overridepublic Object postAfterHttpResponseBodyResult(Object bodyResult, HttpResponse? rsp, Method method, HttpMetadata httpMetadata) {if (bodyResult instanceof BaseRsp){BaseRsp baseRsp (BaseRsp) bodyResult;// 设置baseRsp.setCode(999);}return bodyResult;} } 上面我们分别重写了postBeforeHttpMetadata、postSendHttpRequest、postAfterHttpResponseBodyResult三个生命周期的钩子方法去完成我们的需求在发送请求前对请求体进行加签、在发送请求时动态获取令牌重新构建请求体和打印日志、在发送请求后给响应对象设置code为999。 最后 gitHub代码地址如果觉得项目有用可以star下感谢
http://www.hkea.cn/news/14346116/

相关文章:

  • 国外免费网站域名服务器查询怎么创建音乐网站
  • 东莞建网站服务网站被采集了 一个栏目不收录
  • 湛江网站建设哪家优惠多网页ui设计教程
  • 山西手机响应式网站建设wps2016怎么做网站
  • 织梦手机端网站怎么做公众号推文模板
  • wp做网站难吗wordpress 产品货号
  • 长春seo网站排名优化wordpress禁用头像
  • 怎么做外贸网站seo做的好看的网站
  • 网站建设怎么让百度搜索到东莞免费建站公司
  • 南京网站建设公司排名海淀做网站哪家公司好
  • 如何设置个人网站浙江省外贸公司排名
  • 织梦网站安装阿里云 wordpress 建站
  • 电商网站的建设背景苏州网站建设制作公司小程序开发
  • 深圳精品网站设计gui设计师
  • 企业网站数防泄露怎么做星月网络公司做的网站
  • 澧县网站建设单位网站建设意义
  • 深圳住房和建设局新网站wordpress上传网页
  • 做一个网站成本大概多少钱有免费制作单页的网站吗
  • 嘉兴网站建设系统模板王官网登录
  • 建设网站的工作步骤网页游戏网站556pk游戏福利平台
  • 企业网站的发展历史wordpress 边框
  • 网站电子商务类型美食网站的建设
  • 目录网站模板济南设计网站的公司
  • 网站设计应该遵循哪些原则wordpress用户后台登录界面模板
  • 网站建设很难吗重庆建站管理系统价格
  • 网站建设优化推广杭州网站建站平台源码
  • 运营好还是网站开发好学校网站模板html
  • 哪个网站做h5好用打开这个网站
  • 建设银行个人网站官网网站后台上传用户界面不显示
  • 2023免费网站推广大全做微信的网站叫什么软件