├── commons
├── src
│ └── main
│ │ ├── resources
│ │ └── META-INF
│ │ │ ├── spring.factories
│ │ │ └── spring-configuration-metadata.json
│ │ └── java
│ │ └── com
│ │ └── lyf
│ │ └── springboot
│ │ └── wx
│ │ ├── auto
│ │ ├── WxAutoConfiguration.java
│ │ └── WeChatProperties.java
│ │ ├── WxAuthServiceBase.java
│ │ ├── data
│ │ ├── WeChatAuthResponse.java
│ │ └── WeChatUserInfo.java
│ │ └── utils
│ │ ├── WxConstants.java
│ │ └── JsonHelper.java
└── pom.xml
├── starter-feign
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── META-INF
│ │ │ │ └── spring.factories
│ │ └── java
│ │ │ └── com
│ │ │ └── lyf
│ │ │ └── springboot
│ │ │ └── wechat
│ │ │ ├── WxFeignConfiguration.java
│ │ │ ├── ClientAuthService.java
│ │ │ └── WxAuthClient.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── lyf
│ │ └── springboot
│ │ └── wechat
│ │ └── StarterFeignApplicationTests.java
└── pom.xml
├── starter-httpclient
├── src
│ └── main
│ │ ├── resources
│ │ └── META-INF
│ │ │ └── spring.factories
│ │ └── java
│ │ └── com
│ │ └── lyf
│ │ └── springboot
│ │ └── wx
│ │ ├── auto
│ │ └── WxHttpClientAutoConfiguration.java
│ │ ├── service
│ │ └── ClientAuthService.java
│ │ └── utils
│ │ └── HttpClientUtil.java
└── pom.xml
├── demo
├── src
│ └── main
│ │ ├── resources
│ │ └── application.yml
│ │ └── java
│ │ └── com
│ │ └── lyf
│ │ └── springboot
│ │ └── wx
│ │ └── demo
│ │ ├── SessionConstants.java
│ │ ├── WxDemoApplication.java
│ │ ├── DemoService.java
│ │ ├── WxAuthController.java
│ │ └── LoginInterceptor.java
└── pom.xml
├── .gitignore
├── pom.xml
└── README.md
/commons/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | com.lyf.springboot.wx.auto.WxAutoConfiguration
3 |
--------------------------------------------------------------------------------
/starter-feign/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | com.lyf.springboot.wechat.WxFeignConfiguration
3 |
--------------------------------------------------------------------------------
/starter-httpclient/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | com.lyf.springboot.wx.auto.WxHttpClientAutoConfiguration
3 |
--------------------------------------------------------------------------------
/demo/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | social:
3 | wx:
4 | app-id: 1 # 配置自己申请的appId
5 | app-secret: 2 #配置为自己申请的appSecret
6 | app-name: 3 #此处是为了区分多个app进行的配置 可选
7 | device-type: 2
--------------------------------------------------------------------------------
/demo/src/main/java/com/lyf/springboot/wx/demo/SessionConstants.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.demo;
2 |
3 | public class SessionConstants {
4 |
5 | public static final String SESSION_AGENT_WXUSER = "sessionAgentWxUser";
6 |
7 | public static final String AGENT_WX_ID = "agent_sid";
8 |
9 |
10 | public static final String AUTH_REDIRECT = "redirectUrl";
11 | }
12 |
--------------------------------------------------------------------------------
/starter-feign/src/test/java/com/lyf/springboot/wechat/StarterFeignApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wechat;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class StarterFeignApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | */*.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | nbproject/private/
21 | build/
22 | nbbuild/
23 | dist/
24 | nbdist/
25 | .nb-gradle/
26 | .idea
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/auto/WxAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.auto;
2 |
3 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | /**
7 | *
8 | * @author 永锋
9 | * @date 2017/9/28
10 | */
11 | @Configuration
12 | @EnableConfigurationProperties(WeChatProperties.class)
13 | public class WxAutoConfiguration {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/lyf/springboot/wx/demo/WxDemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.demo;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 |
7 | /**
8 | * Created by 永锋 on 2017/9/28.
9 | */
10 | @SpringBootApplication
11 | @ComponentScan(basePackages = {"com.lyf.springboot"})
12 | public class WxDemoApplication {
13 | public static void main(String[] args) {
14 | SpringApplication.run(WxDemoApplication.class, args);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/commons/src/main/resources/META-INF/spring-configuration-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "properties": [
3 | {
4 | "name": "spring.social.wx.app-id",
5 | "type": "java.lang.String",
6 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
7 | },
8 | {
9 | "name": "spring.social.wx.app-secret",
10 | "type": "java.lang.String",
11 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
12 | },
13 | {
14 | "name": "spring.social.wx.app-name",
15 | "type": "java.lang.String",
16 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
17 | },
18 | {
19 | "name": "spring.social.wx.device-type",
20 | "type": "java.lang.String",
21 | "description": "wx platform type, 1 for app, 2 for web",
22 | "defaultValue": 1,
23 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
24 | }
25 | ],
26 | "hints": []
27 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/lyf/springboot/wx/demo/DemoService.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.demo;
2 |
3 | import com.lyf.springboot.wx.WxAuthServiceBase;
4 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
5 | import com.lyf.springboot.wx.data.WeChatUserInfo;
6 | import org.springframework.stereotype.Service;
7 |
8 | /**
9 | * DemoService
10 | *
11 | * @author yongfeng.liu
12 | */
13 | @Service
14 | public class DemoService {
15 | private final WxAuthServiceBase wxAuthService;
16 |
17 | public DemoService(WxAuthServiceBase wxAuthService) {
18 | this.wxAuthService = wxAuthService;
19 | }
20 |
21 | public WeChatUserInfo authAndUser(String code){
22 | WeChatAuthResponse authResponse = wxAuthService.auth(code);
23 | if(authResponse == null) {
24 | return null;
25 | }
26 | return wxAuthService.userInfo(authResponse.getAccessToken(), authResponse.getOpenid());
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/WxAuthServiceBase.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx;
2 |
3 | import com.lyf.springboot.wx.auto.WeChatProperties;
4 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
5 | import com.lyf.springboot.wx.data.WeChatUserInfo;
6 |
7 | /**
8 | * Created by 永锋 on 2017/9/28.
9 | */
10 | public abstract class WxAuthServiceBase {
11 | protected WeChatProperties weChatProperties;
12 |
13 | public WxAuthServiceBase(WeChatProperties weChatProperties) {
14 | this.weChatProperties = weChatProperties;
15 | }
16 |
17 | /**
18 | * 微信授权
19 | *
20 | * @param authorizationCode
21 | * @return
22 | */
23 | public abstract WeChatAuthResponse auth(String authorizationCode);
24 |
25 | /**
26 | * 获取用户的微信个人信息
27 | *
28 | * @param accessToken
29 | * @param openId
30 | * @return
31 | */
32 | public abstract WeChatUserInfo userInfo(String accessToken, String openId);
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/data/WeChatAuthResponse.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.data;
2 |
3 |
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5 | import com.fasterxml.jackson.databind.PropertyNamingStrategy;
6 | import com.fasterxml.jackson.databind.annotation.JsonNaming;
7 | import lombok.Data;
8 |
9 | /**
10 | * right result { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN",
11 | * "openid":"OPENID", "scope":"SCOPE", "unionid":"o6_bmasdasdsad6_2sgVt1231234" }
12 | */
13 | @JsonIgnoreProperties(ignoreUnknown = true)
14 | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
15 | @Data
16 | public class WeChatAuthResponse {
17 |
18 | private int errcode;
19 |
20 | private String errmsg;
21 |
22 | private String accessToken;
23 |
24 | private int expiresIn;
25 |
26 | private String refreshToken;
27 |
28 | private String openid;
29 |
30 | private String scope;
31 |
32 | private String unionid;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/starter-httpclient/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | wechat-parent
7 | com.lyf.springboot.wechat
8 | 0.0.2-SNAPSHOT
9 | ../pom.xml
10 |
11 | 4.0.0
12 |
13 | starter-httpclient
14 |
15 |
16 |
17 | org.apache.httpcomponents
18 | httpclient
19 |
20 |
21 |
22 | ${project.groupId}
23 | commons
24 | ${project.version}
25 |
26 |
27 | org.projectlombok
28 | lombok
29 | provided
30 |
31 |
32 |
--------------------------------------------------------------------------------
/starter-httpclient/src/main/java/com/lyf/springboot/wx/auto/WxHttpClientAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.auto;
2 |
3 | import com.lyf.springboot.wx.WxAuthServiceBase;
4 | import com.lyf.springboot.wx.service.ClientAuthService;
5 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
7 | import org.springframework.boot.context.properties.ConfigurationProperties;
8 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | /**
13 | *
14 | * @author 永锋
15 | * @date 2017/9/28
16 | */
17 | @Configuration
18 | @AutoConfigureAfter(WxAutoConfiguration.class)
19 | public class WxHttpClientAutoConfiguration {
20 | @Bean(name = "wxAuthService")
21 | @ConditionalOnMissingBean(WxAuthServiceBase.class)
22 | public WxAuthServiceBase wxAuthService(WeChatProperties weChatProperties){
23 | return new ClientAuthService(weChatProperties);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/starter-feign/src/main/java/com/lyf/springboot/wechat/WxFeignConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wechat;
2 |
3 | import com.lyf.springboot.wx.WxAuthServiceBase;
4 | import com.lyf.springboot.wx.auto.WeChatProperties;
5 | import com.lyf.springboot.wx.auto.WxAutoConfiguration;
6 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
8 | import org.springframework.cloud.openfeign.EnableFeignClients;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | /**
13 | * 使用feign client 访问微信
14 | *
15 | * @author yongfeng.liu
16 | */
17 | @Configuration
18 | @EnableFeignClients(clients = {WxAuthClient.class})
19 | @AutoConfigureAfter(WxAutoConfiguration.class)
20 | public class WxFeignConfiguration {
21 |
22 | @Bean
23 | @ConditionalOnMissingBean(WxAuthServiceBase.class)
24 | public WxAuthServiceBase wxAuthService(WeChatProperties chatProperties, WxAuthClient wxAuthClient) {
25 | return new ClientAuthService(chatProperties, wxAuthClient);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/starter-feign/src/main/java/com/lyf/springboot/wechat/ClientAuthService.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wechat;
2 |
3 | import com.lyf.springboot.wx.WxAuthServiceBase;
4 | import com.lyf.springboot.wx.auto.WeChatProperties;
5 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
6 | import com.lyf.springboot.wx.data.WeChatUserInfo;
7 |
8 | /**
9 | * @author
10 | */
11 | public class ClientAuthService extends WxAuthServiceBase {
12 | private WxAuthClient wxAuthClient;
13 |
14 | public ClientAuthService(WeChatProperties weChatProperties, WxAuthClient wxAuthClient) {
15 | super(weChatProperties);
16 | this.wxAuthClient = wxAuthClient;
17 | }
18 |
19 | @Override
20 | public WeChatAuthResponse auth(String authorizationCode) {
21 | return wxAuthClient.auth(this.weChatProperties.getAppId(), this.weChatProperties.getAppSecret(),
22 | authorizationCode, WxAuthClient.GRANT_TYPE_AUTH);
23 | }
24 |
25 | @Override
26 | public WeChatUserInfo userInfo(String accessToken, String openId) {
27 | return wxAuthClient.userInfo(accessToken, openId, WxAuthClient.LANG_CHINA);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/utils/WxConstants.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.utils;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.net.URLEncoder;
5 | import java.nio.charset.StandardCharsets;
6 |
7 | /**
8 | *
9 | * @author 永锋
10 | * @date 2016/11/23
11 | */
12 | public interface WxConstants {
13 | String API_HOST = "https://api.weixin.qq.com";
14 | String AUTH_PATH = "/sns/oauth2/access_token";
15 | String USER_INFO_PATH = "/sns/userinfo";
16 |
17 | String MEDIA_DOWN_URL = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";
18 |
19 | String WX_LOGIN_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s"
20 | + "&redirect_uri=%s&response_type=code&scope=snsapi_userinfo";
21 |
22 |
23 | /**
24 | * 微信授权链接
25 | * @param appId
26 | * @param redirectUrl
27 | * @return
28 | * @throws UnsupportedEncodingException
29 | */
30 | static String loginUrl(String appId, String redirectUrl) throws UnsupportedEncodingException {
31 | return String.format(WxConstants.WX_LOGIN_URL, appId, URLEncoder.encode(redirectUrl, StandardCharsets.UTF_8.name()));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/auto/WeChatProperties.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.auto;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 |
5 | /**
6 | * Created by 永锋 on 2016/11/22.
7 | */
8 | @ConfigurationProperties(
9 | prefix = "spring.social.wx"
10 | )
11 | public class WeChatProperties {
12 |
13 | private String appId;
14 | private String appSecret;
15 | private String appName;
16 | private int deviceType;
17 |
18 | public String getAppName() {
19 | return appName;
20 | }
21 |
22 | public void setAppName(String appName) {
23 | this.appName = appName;
24 | }
25 |
26 | public int getDeviceType() {
27 | return deviceType;
28 | }
29 |
30 | public void setDeviceType(int deviceType) {
31 | this.deviceType = deviceType;
32 | }
33 |
34 | public String getAppId() {
35 | return appId;
36 | }
37 |
38 | public void setAppId(String appId) {
39 | this.appId = appId;
40 | }
41 |
42 | public String getAppSecret() {
43 | return appSecret;
44 | }
45 |
46 | public void setAppSecret(String appSecret) {
47 | this.appSecret = appSecret;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/starter-feign/src/main/java/com/lyf/springboot/wechat/WxAuthClient.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wechat;
2 |
3 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
4 | import com.lyf.springboot.wx.data.WeChatUserInfo;
5 | import com.lyf.springboot.wx.utils.WxConstants;
6 | import org.springframework.cloud.openfeign.FeignClient;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestParam;
9 |
10 | /**
11 | * @author
12 | */
13 |
14 | @FeignClient(name = "wxAuthClient", url = WxConstants.API_HOST)
15 | public interface WxAuthClient {
16 | String GRANT_TYPE_AUTH = "authorization_code";
17 | String LANG_CHINA = "zh_CN";
18 |
19 |
20 | @GetMapping(WxConstants.AUTH_PATH)
21 | WeChatAuthResponse auth(@RequestParam("appid") String appId,
22 | @RequestParam("secret") String secret,
23 | @RequestParam("code") String authorizationCode,
24 | @RequestParam("grant_type") String grantType);
25 |
26 | @GetMapping(WxConstants.USER_INFO_PATH)
27 | WeChatUserInfo userInfo(@RequestParam("openid") String openId,
28 | @RequestParam("access_token") String accessToken,
29 | @RequestParam("lang") String lang);
30 | }
31 |
--------------------------------------------------------------------------------
/demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | wechat-parent
7 | com.lyf.springboot.wechat
8 | 0.0.2-SNAPSHOT
9 | ../pom.xml
10 |
11 | 4.0.0
12 |
13 | demo
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-starter-web
19 |
20 |
25 |
26 |
27 | com.lyf.springboot.wechat
28 | starter-feign
29 | 0.0.2-SNAPSHOT
30 |
31 |
32 |
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-maven-plugin
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/utils/JsonHelper.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.utils;
2 |
3 | import com.fasterxml.jackson.core.type.TypeReference;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.io.IOException;
10 |
11 | public class JsonHelper {
12 |
13 | private static Logger logger = LoggerFactory.getLogger(JsonHelper.class);
14 |
15 | private static ObjectMapper mapper = new ObjectMapper();
16 |
17 | public static String toJsonString(Object o) {
18 | if (o == null) {
19 | return null;
20 | }
21 |
22 | try {
23 | String jsonString = mapper.writeValueAsString(o);
24 | return jsonString;
25 | } catch (IOException e) {
26 | logger.error("unknow error: {}", e);
27 | return null;
28 | }
29 | }
30 |
31 | public static T fromJsonString(String json, Class valueType) {
32 | if (StringUtils.isBlank(json)) {
33 | return null;
34 | }
35 |
36 | try {
37 | return mapper.readValue(json, valueType);
38 | } catch (IOException e) {
39 | logger.error("can't parse json string: {}", json, e);
40 | e.printStackTrace();
41 | return null;
42 | }
43 | }
44 |
45 | public static T fromJsonString(String json, TypeReference type) {
46 | if (StringUtils.isBlank(json)) {
47 | return null;
48 | }
49 | try {
50 | return mapper.readValue(json, type);
51 | } catch (IOException e) {
52 | logger.error("can't parse json string: {}", json, e);
53 | return null;
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/commons/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | wechat-parent
7 | com.lyf.springboot.wechat
8 | 0.0.2-SNAPSHOT
9 | ../pom.xml
10 |
11 | 4.0.0
12 |
13 | commons
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-autoconfigure
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-logging
24 |
25 |
26 | org.apache.commons
27 | commons-lang3
28 |
29 |
30 | com.fasterxml.jackson.core
31 | jackson-core
32 |
33 |
34 | com.fasterxml.jackson.core
35 | jackson-databind
36 |
37 |
38 | commons-collections
39 | commons-collections
40 |
41 |
42 | org.projectlombok
43 | lombok
44 | provided
45 |
46 |
47 |
--------------------------------------------------------------------------------
/commons/src/main/java/com/lyf/springboot/wx/data/WeChatUserInfo.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.data;
2 |
3 |
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5 | import com.fasterxml.jackson.databind.PropertyNamingStrategy;
6 | import com.fasterxml.jackson.databind.annotation.JsonNaming;
7 | import lombok.Data;
8 |
9 | import java.util.Arrays;
10 |
11 | /**
12 | * {
13 | * "openid":"omZu7t_MZ48ZeXLv6HV77z8_xxx",
14 | * "nickname":"蒼白",
15 | * "sex":1,
16 | * "language":"zh_CN",
17 | * "city":"西城",
18 | * "province":"北京",
19 | * "country":"中国",
20 | * "headimgurl":"http:\/\/wx.qlogo.cn\/mmopen\/ajNVdqHZLLBSVTcnqBd5s47NbibExsxoRlo0uVfppEBbjNmgUxSnTdAXtS8pcpZMicVsTO9VpwVv2aexOZxXODUQ\/0",
21 | * "privilege":[],
22 | * "unionid":"oXqrGt6JRRZJDQDEQAFUkabc"
23 | * }
24 | */
25 | @JsonIgnoreProperties(ignoreUnknown = true)
26 | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
27 | @Data
28 | public class WeChatUserInfo {
29 |
30 | private static final int SEX_MAN = 1;
31 |
32 | private static final int SEX_WOMEN = 2;
33 |
34 | private String openid;
35 |
36 | private String nickname;
37 |
38 | private int sex;
39 |
40 | private String province;
41 |
42 | private String city;
43 |
44 | private String country;
45 |
46 | private String headimgurl;
47 |
48 | private String srcimg;
49 |
50 | private String[] privilege;
51 |
52 | private String unionid;
53 |
54 | private String language;
55 |
56 | public void beMan() {
57 | this.sex = SEX_MAN;
58 | }
59 | public void beWomen() {
60 | this.sex = SEX_WOMEN;
61 | }
62 |
63 | @Override
64 | public String toString() {
65 | return "WechatUserInfo{" +
66 | "openid='" + openid + '\'' +
67 | ", nickname='" + nickname + '\'' +
68 | ", sex=" + sex +
69 | ", province='" + province + '\'' +
70 | ", city='" + city + '\'' +
71 | ", country='" + country + '\'' +
72 | ", headimgurl='" + headimgurl + '\'' +
73 | ", privilege=" + Arrays.toString(privilege) +
74 | ", unionid='" + unionid + '\'' +
75 | '}';
76 | }
77 |
78 | public String getLanguage() {
79 | return language;
80 | }
81 |
82 | public void setLanguage(String language) {
83 | this.language = language;
84 | }
85 |
86 | public String getSrcimg() {
87 | return srcimg;
88 | }
89 |
90 | public void setSrcimg(String srcimg) {
91 | this.srcimg = srcimg;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/starter-httpclient/src/main/java/com/lyf/springboot/wx/service/ClientAuthService.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.service;
2 |
3 | import com.lyf.springboot.wx.WxAuthServiceBase;
4 | import com.lyf.springboot.wx.auto.WeChatProperties;
5 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
6 | import com.lyf.springboot.wx.data.WeChatUserInfo;
7 | import com.lyf.springboot.wx.utils.HttpClientUtil;
8 | import com.lyf.springboot.wx.utils.JsonHelper;
9 | import com.lyf.springboot.wx.utils.WxConstants;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | /**
14 | * @author 永锋
15 | * @date 2017/9/28
16 | */
17 | @Slf4j
18 | public class ClientAuthService extends WxAuthServiceBase {
19 |
20 | public ClientAuthService(WeChatProperties weChatProperties) {
21 | super(weChatProperties);
22 | }
23 |
24 | @Override
25 | public WeChatAuthResponse auth(String authorizationCode) {
26 | if (StringUtils.isEmpty(authorizationCode) || "null".equalsIgnoreCase(authorizationCode)) {
27 | log.warn("error code: {}", authorizationCode);
28 | return null;
29 | }
30 |
31 | String accessUrl = getWXAccessUrl(authorizationCode, weChatProperties.getAppId(),
32 | weChatProperties.getAppSecret());
33 | log.info("accessUrl:{}", accessUrl);
34 | String result = HttpClientUtil.getHttpsContent(accessUrl);
35 | WeChatAuthResponse response = JsonHelper.fromJsonString(result, WeChatAuthResponse.class);
36 |
37 | if (response == null || response.getErrcode() != 0 || StringUtils.isBlank(response.getOpenid())) {
38 | return null;
39 | }
40 | return response;
41 | }
42 |
43 | @Override
44 | public WeChatUserInfo userInfo(String accessToken, String openId) {
45 | String userInfoUrl = getWxUserInfoUrl(accessToken, openId);
46 | log.info("userinfo url: {}", userInfoUrl);
47 | String userInfo = HttpClientUtil.getHttpsContent(userInfoUrl);
48 | log.info("result user info: {}", userInfo);
49 | return JsonHelper.fromJsonString(userInfo, WeChatUserInfo.class);
50 | }
51 |
52 | private static String getWXAccessUrl(String code, String appId, String secret) {
53 | return WxConstants.API_HOST + WxConstants.AUTH_PATH + "?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
54 | }
55 |
56 | private static String getWxUserInfoUrl(String accessToken, String openid) {
57 | return WxConstants.API_HOST + WxConstants.USER_INFO_PATH + "?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/starter-feign/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | wechat-parent
7 | com.lyf.springboot.wechat
8 | 0.0.2-SNAPSHOT
9 | ../pom.xml
10 |
11 | starter-feign
12 | 0.0.2-SNAPSHOT
13 | starter-feign
14 | WeChat auth for Spring Boot
15 |
16 |
17 | 1.8
18 | Hoxton.SR6
19 |
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-openfeign
25 |
26 |
27 | ${project.groupId}
28 | commons
29 | ${project.version}
30 |
31 |
32 |
33 | org.projectlombok
34 | lombok
35 | true
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-test
40 | test
41 |
42 |
43 | org.junit.vintage
44 | junit-vintage-engine
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.springframework.cloud
54 | spring-cloud-dependencies
55 | ${spring-cloud.version}
56 | pom
57 | import
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-maven-plugin
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.lyf.springboot.wechat
7 | wechat-parent
8 | 0.0.2-SNAPSHOT
9 |
10 | commons
11 | demo
12 | starter-httpclient
13 | starter-feign
14 |
15 | pom
16 |
17 | wechat-parent
18 | Spring Boot WeChat Starter
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-parent
23 | 2.3.1.RELEASE
24 |
25 |
26 |
27 |
28 | UTF-8
29 | UTF-8
30 | 1.8
31 | 1.18.12
32 | Hoxton.SR6
33 |
34 |
35 |
36 |
37 | JohnsonLow(yongfeng.liu)
38 | 272462809@qq.com
39 | github.com/JohnsonLow
40 | +8
41 |
42 |
43 |
44 |
45 |
46 | org.apache.commons
47 | commons-lang3
48 | 3.10
49 |
50 |
51 |
52 | commons-collections
53 | commons-collections
54 | 3.2.2
55 |
56 |
57 |
58 | org.springframework.cloud
59 | spring-cloud-dependencies
60 | ${spring-cloud.version}
61 | pom
62 | import
63 |
64 |
65 | org.projectlombok
66 | lombok
67 | ${lombok.version}
68 | provided
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | maven-compiler-plugin
77 |
78 | ${java.version}
79 | ${java.version}
80 | ${project.build.sourceEncoding}
81 |
82 |
83 |
84 | maven-resources-plugin
85 |
86 | ${project.build.sourceEncoding}
87 | true
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/lyf/springboot/wx/demo/WxAuthController.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.demo;
2 |
3 | import com.lyf.springboot.wx.auto.WeChatProperties;
4 | import com.lyf.springboot.wx.data.WeChatUserInfo;
5 | import com.lyf.springboot.wx.utils.WxConstants;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.ui.Model;
11 | import org.springframework.web.bind.annotation.PathVariable;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import javax.servlet.http.HttpSession;
16 | import java.io.UnsupportedEncodingException;
17 |
18 | /**
19 | * 此demo用于处理微信公众号授权
20 | * Created by 永锋 on 2017/9/28.
21 | */
22 | @Controller
23 | @RequestMapping("/wx")
24 | public class WxAuthController {
25 | private static final String AUTH_REDIRECT = "redirectUrl";
26 | private static final Logger logger = LoggerFactory.getLogger(WxAuthController.class);
27 |
28 | @Autowired
29 | private DemoService demoService;
30 | @Autowired
31 | private HttpServletRequest request;
32 | @Autowired
33 | private WeChatProperties weChatProperties;
34 |
35 | /**
36 | * @param webType 3页面点击授权
37 | * @return
38 | * @throws UnsupportedEncodingException
39 | */
40 | @RequestMapping("/{webType}")
41 | public String redirect(@PathVariable("webType") int webType) throws UnsupportedEncodingException {
42 | if (webType == 3) {
43 | String refer = request.getHeader("Referer");
44 | logger.info("refer:{}", refer);
45 | request.getSession().setAttribute(SessionConstants.AUTH_REDIRECT, refer);
46 | }
47 | return "redirect:" + buildRedirectUrl();
48 | }
49 |
50 | /**
51 | * 使用即答服务号授权
52 | *
53 | * @return
54 | * @throws UnsupportedEncodingException
55 | */
56 | private String buildRedirectUrl() throws UnsupportedEncodingException {
57 | //TODO 此处应根据实际的域名修改
58 | String redirectUrl = "http://localhost/" + request.getServerName() + "/wx/auth";
59 | String redirect_url = WxConstants.loginUrl(weChatProperties.getAppId(), redirectUrl);
60 | logger.info("url: {}", redirect_url);
61 | return redirect_url;
62 | }
63 |
64 | @RequestMapping("/auth")
65 | public String auth(String code, String state, Model model) {
66 | String refer = request.getHeader("Referer");
67 | try {
68 | logger.info("wx auth state : {}", state);
69 |
70 | WeChatUserInfo wxUser = demoService.authAndUser(code);
71 | if (wxUser == null) {
72 | model.addAttribute("errMsg", "微信授权失败,请返回重试");
73 | model.addAttribute("tryUrl", "http://v.51ruhang.cn");
74 | return "error";
75 | }
76 | HttpSession session = request.getSession();
77 | String redirectUrl = (String) session.getAttribute(AUTH_REDIRECT);
78 | if (redirectUrl != null) {
79 | session.removeAttribute(AUTH_REDIRECT);
80 | return "redirect:" + redirectUrl;
81 | } else {
82 | return "redirect:" + refer;
83 | }
84 | } catch (Exception exception) {
85 | return "redirect:" + refer;
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/lyf/springboot/wx/demo/LoginInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.demo;
2 |
3 |
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.stereotype.Component;
8 | import org.springframework.web.servlet.ModelAndView;
9 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 | import javax.servlet.http.HttpServletResponse;
13 | import javax.servlet.http.HttpSession;
14 | import java.io.IOException;
15 | import java.net.URLEncoder;
16 | import java.util.HashSet;
17 | import java.util.Set;
18 |
19 | @Component
20 | public class LoginInterceptor extends HandlerInterceptorAdapter {
21 |
22 | private static Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
23 |
24 | private static Set jumpUrls = new HashSet<>();
25 | static {
26 | jumpUrls.add("/article/list");
27 | jumpUrls.add("/article/list-data");
28 | // jumpUrls.add("")
29 | }
30 |
31 |
32 | public LoginInterceptor() {
33 | }
34 |
35 |
36 | @Override
37 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
38 | throws Exception {
39 | HttpSession session = request.getSession();
40 | if(session.getAttribute(SessionConstants.SESSION_AGENT_WXUSER) != null){
41 | response.setHeader("Cache-Control","no-store");
42 | response.setHeader("Pragma", "no-cache");
43 | response.setDateHeader("Expires", 0);
44 | return true;
45 | }
46 |
47 | return checkWxBrowser(request, response);
48 | }
49 |
50 | private boolean checkWxBrowser(HttpServletRequest request, HttpServletResponse response) throws IOException {
51 | StringBuffer requestUrl = request.getRequestURL();
52 | String queryParam = request.getQueryString();
53 | String refUrl = requestUrl.toString();
54 | if (StringUtils.isNotBlank(queryParam)) {
55 | refUrl += "?" + queryParam;
56 | }
57 | if(jumpUrls.contains(request.getRequestURI())){
58 | if(isWxBrowser(request)){
59 | request.getSession().setAttribute(SessionConstants.AUTH_REDIRECT, refUrl);
60 | response.sendRedirect(String.format("/agent_wx_auth/%s?url=%s", webType(),
61 | URLEncoder.encode(refUrl, "UTF8")));
62 | return false;
63 | } else {
64 | response.setHeader("Cache-Control","no-store");
65 | response.setHeader("Pragma", "no-cache");
66 | response.setDateHeader("Expires", 0);
67 | return true;
68 | }
69 | } else {
70 | request.getSession().setAttribute(SessionConstants.AUTH_REDIRECT, refUrl);
71 | response.sendRedirect(String.format("/agent_wx_auth/%s?url=%s", webType(),
72 | URLEncoder.encode(refUrl, "UTF8")));
73 | return false;
74 | }
75 | }
76 | private static boolean isWxBrowser(HttpServletRequest request){
77 | String userAgent = request.getHeader("user-agent");
78 | return userAgent.contains("MicroMessenger");
79 | }
80 |
81 | protected int webType (){
82 | return 1;
83 | }
84 | @Override
85 | public void postHandle(
86 | HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
87 | throws Exception {
88 | }
89 |
90 | @Override
91 | public void afterCompletion(
92 | HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
93 | throws Exception {
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## spring-boot-wechat-starter
2 |
3 | 该项目主要功能是微信授权登陆及获取用户信息,共有两个模块
4 | - wechat-starter 主要功能模块
5 | - demo 测试模块
6 | ###wechat-starter模块
7 | #### jar依赖
8 | ```xml
9 |
10 | org.springframework.boot
11 | spring-boot-autoconfigure
12 |
13 |
14 | org.springframework.boot
15 | spring-boot-starter-logging
16 |
17 |
18 | org.apache.commons
19 | commons-lang3
20 |
21 |
22 | com.fasterxml.jackson.core
23 | jackson-core
24 |
25 |
26 | com.fasterxml.jackson.core
27 | jackson-databind
28 |
29 |
30 | org.apache.httpcomponents
31 | httpclient
32 |
33 |
34 | commons-collections
35 | commons-collections
36 |
37 | ```
38 | #### 主要功能类
39 | 1. 配置类
40 | ```java
41 | @ConfigurationProperties(prefix = "spring.social.wx")
42 | public class WxProperties extends SocialProperties {
43 |
44 | private String appName;
45 |
46 | private int deviceType;
47 |
48 | public String getAppName() {
49 | return appName;
50 | }
51 |
52 | public void setAppName(String appName) {
53 | this.appName = appName;
54 | }
55 |
56 | public int getDeviceType() {
57 | return deviceType;
58 | }
59 |
60 | public void setDeviceType(int deviceType) {
61 | this.deviceType = deviceType;
62 | }
63 | }
64 | ```
65 | 2.逻辑类
66 | ```java
67 | package com.lyf.springboot.wx;
68 |
69 | import com.lyf.springboot.wx.auto.WeChatProperties;
70 | import com.lyf.springboot.wx.data.WeChatAuthResponse;
71 | import com.lyf.springboot.wx.data.WeChatUserInfo;
72 | import com.lyf.springboot.wx.utils.HttpClientUtil;
73 | import com.lyf.springboot.wx.utils.JsonHelper;
74 | import com.lyf.springboot.wx.utils.WxConstants;
75 | import org.apache.commons.lang3.StringUtils;
76 | import org.slf4j.Logger;
77 | import org.slf4j.LoggerFactory;
78 | import org.springframework.beans.factory.annotation.Autowired;
79 |
80 | /**
81 | * Created by 永锋 on 2017/9/28.
82 | */
83 | public class WxAuthService {
84 | private static Logger logger = LoggerFactory.getLogger(WxAuthService.class);
85 | @Autowired
86 | private WxProperties wxProperties;
87 |
88 | public WxAuthService() {
89 | }
90 |
91 | /**
92 | * 进行微信授权,获取用户信息 存入进本库 和 关系库
93 | * @param code
94 | * @return
95 | */
96 | public WeChatUserInfo auth(String code){
97 | if(StringUtils.isEmpty(code) || "null".equalsIg(code)){
98 | logger.warn("error code: {}", code);
99 | return null;
100 | }
101 |
102 | String accessUrl = WxHelper.getWXAccessUrl(code, wxProperties.getAppId(),
103 | wxProperties.getAppSecret());
104 | logger.info("accessUrl:{}", accessUrl);
105 | String result = HttpClientUtil.getHttpsContent(accessUrl);
106 | WeChatAuthResponse response = JsonHelper.fromJsonString(result, WeChatAuthResponse.class);
107 |
108 | if(response == null || response.getErrcode() != 0 || StringUtils.isBlank(response.getOpenid())){
109 | return null;
110 | }
111 | WeChatUserInfo userInfo = WxHelper.requestUserInfo(response.getAccess_token(), response.getOpenid());
112 | if(userInfo == null || StringUtils.isBlank(userInfo.getUnionid())){
113 | return null;
114 | }
115 | return userInfo;
116 | }
117 | }
118 | ```
119 | 3. 自动注入类
120 | ```java
121 | package com.lyf.springboot.wx.auto;
122 |
123 | import com.lyf.springboot.wx.WxAuthService;
124 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
125 | import org.springframework.context.annotation.Bean;
126 | import org.springframework.context.annotation.Configuration;
127 |
128 | /**
129 | * Created by 永锋 on 2017/9/28.
130 | */
131 | @Configuration
132 | @EnableConfigurationProperties(WxProperties.class)
133 | public class WxAutoConfiguration {
134 | @Bean(name = "wxAuthService")
135 | public WxAuthService wxAuthService(){
136 | return new WxAuthService();
137 | }
138 | }
139 | ```
140 | 4.配置自动注入类,在resources/META-INF/目录下创建spring.factories文件
141 |
142 | ```
143 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
144 | com.lyf.springboot.wx.auto.WxAutoConfiguration
145 | ```
146 |
147 | 5. 对WxProperties类的属性进行配置,在resources/META-INF/目录下创建spring-configuration-metadata.json文件
148 | ```javascript
149 | {
150 | "properties": [
151 | {
152 | "name": "spring.social.wx.app-id",
153 | "type": "java.lang.String",
154 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
155 | },
156 | {
157 | "name": "spring.social.wx.app-secret",
158 | "type": "java.lang.String",
159 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
160 | },
161 | {
162 | "name": "spring.social.wx.app-name",
163 | "type": "java.lang.String",
164 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
165 | },
166 | {
167 | "name": "spring.social.wx.device-type",
168 | "type": "java.lang.String",
169 | "description": "wx platform type, 1 for app, 2 for web",
170 | "defaultValue": 1,
171 | "sourceType": "com.lyf.springboot.wx.auto.WeChatProperties"
172 | }
173 | ],
174 | "hints": []
175 | }
176 | ```
177 | ### starter的使用
178 | > 0.0.2中更新了spring boot为2.3.1,如果需要在自己项目中使用,建议根据自己的springboot版本进行调整
179 | 1. maven中引入starter-feign
180 | ```xml
181 |
182 |
183 | com.lyf.springboot.wechat
184 | starter-feign
185 | 0.0.2-SNAPSHOT
186 |
187 |
188 |
189 |
196 | ```
197 | 2. 在application.yml中配置自己的微信App信息
198 | ```yml
199 | spring:
200 | social:
201 | wx:
202 | app-id: # 配置自己申请的appId
203 | app-secret: #配置为自己申请的appSecret
204 | app-name: #此处是为了区分多个app进行的配置 可选
205 | device-type: 2
206 | ```
207 | 3. 在自己的controller里面调用wechat-starter的逻辑类,实现授权登陆(获取用户信息)
208 |
--------------------------------------------------------------------------------
/starter-httpclient/src/main/java/com/lyf/springboot/wx/utils/HttpClientUtil.java:
--------------------------------------------------------------------------------
1 | package com.lyf.springboot.wx.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.http.HttpStatus;
5 | import org.apache.http.client.HttpRequestRetryHandler;
6 | import org.apache.http.client.entity.UrlEncodedFormEntity;
7 | import org.apache.http.client.methods.CloseableHttpResponse;
8 | import org.apache.http.client.methods.HttpGet;
9 | import org.apache.http.client.methods.HttpPost;
10 | import org.apache.http.client.protocol.HttpClientContext;
11 | import org.apache.http.config.ConnectionConfig;
12 | import org.apache.http.config.Registry;
13 | import org.apache.http.config.RegistryBuilder;
14 | import org.apache.http.config.SocketConfig;
15 | import org.apache.http.conn.socket.ConnectionSocketFactory;
16 | import org.apache.http.conn.socket.PlainConnectionSocketFactory;
17 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
18 | import org.apache.http.conn.ssl.SSLContextBuilder;
19 | import org.apache.http.conn.ssl.TrustStrategy;
20 | import org.apache.http.impl.client.CloseableHttpClient;
21 | import org.apache.http.impl.client.HttpClients;
22 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
23 | import org.apache.http.message.BasicNameValuePair;
24 | import org.apache.http.protocol.HttpContext;
25 | import org.apache.http.util.EntityUtils;
26 |
27 | import javax.net.ssl.SSLContext;
28 | import java.io.IOException;
29 | import java.net.URI;
30 | import java.nio.charset.StandardCharsets;
31 | import java.security.KeyManagementException;
32 | import java.security.KeyStoreException;
33 | import java.security.NoSuchAlgorithmException;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 | import java.util.Map;
37 | import java.util.Set;
38 |
39 | @Slf4j
40 | public class HttpClientUtil {
41 |
42 | public static final int DEFAULE_RETRY = 3;
43 |
44 | public static final int KMAXTOTAL = 2000;
45 |
46 | public static final int MAXPERROUTE = 2000;
47 |
48 | public static CloseableHttpClient buildHttpClient() {
49 | return buildHttpClient(DEFAULE_RETRY, KMAXTOTAL, MAXPERROUTE);
50 | }
51 |
52 | /**
53 | * create http client
54 | *
55 | * @param retryNum 重试次数
56 | * @param maxTotal 最大连接数
57 | * @param maxPerRoute 每个路由基础的连接数
58 | * @return
59 | */
60 | public static CloseableHttpClient buildHttpClient(Integer retryNum, Integer maxTotal,
61 | Integer maxPerRoute) {
62 | final int kRetryNum = retryNum == null ? DEFAULE_RETRY : retryNum;
63 |
64 | HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {
65 | if (executionCount > kRetryNum) {
66 | // Do not retry if over max retry count
67 | return false;
68 | }
69 | return true;
70 | };
71 |
72 | final int kMaxTotal = maxTotal == null ? KMAXTOTAL : maxTotal;
73 | final int kMaxPerRoute = maxPerRoute == null ? MAXPERROUTE : maxPerRoute;
74 |
75 | Registry r =
76 | RegistryBuilder.create()
77 | .register("http", PlainConnectionSocketFactory.INSTANCE).build();
78 |
79 | PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
80 |
81 | // ConnectionConfig
82 | ConnectionConfig connectionConfig = ConnectionConfig.custom().setCharset(StandardCharsets.UTF_8).build();
83 | SocketConfig socketConfig =
84 | SocketConfig.custom().setTcpNoDelay(true).setSoKeepAlive(true).setSoReuseAddress(true)
85 | .build();
86 | cm.setDefaultConnectionConfig(connectionConfig);
87 | cm.setDefaultSocketConfig(socketConfig);
88 | // 将最大连接数增加到2000
89 | cm.setMaxTotal(kMaxTotal);
90 | // 将每个路由基础的连接增加到2000
91 | cm.setDefaultMaxPerRoute(kMaxPerRoute);
92 |
93 | return HttpClients.custom().setConnectionManager(cm).setRetryHandler(retryHandler).build();
94 | }
95 |
96 | public static String getContent(String requestUrl, Map header) {
97 | CloseableHttpResponse response = null;
98 | CloseableHttpClient httpClient = HttpClients.createDefault();
99 | String returnValue = null;
100 | log.debug("request url: {}", requestUrl);
101 | try {
102 |
103 | HttpGet httpGet = new HttpGet(requestUrl);
104 |
105 | if (header != null && header.size() > 0) {
106 | for (Map.Entry entry : header.entrySet()) {
107 | httpGet.addHeader(entry.getKey(), entry.getValue());
108 | }
109 | }
110 |
111 | HttpContext context = HttpClientContext.create();
112 |
113 | response = httpClient.execute(httpGet, context);
114 | int statusCode = response.getStatusLine().getStatusCode();
115 |
116 | returnValue = new String(EntityUtils.toByteArray(response.getEntity()), StandardCharsets.UTF_8);
117 | log.debug(returnValue);
118 |
119 | log.debug("status code {}", statusCode);
120 | if (statusCode != HttpStatus.SC_OK) {
121 | throw new RuntimeException("目前提交不了,联系码农一下吧 :)");
122 | }
123 |
124 | } catch (Exception e) {
125 | log.error("Http Get Content", e);
126 | } finally {
127 | try {
128 | closeHttpResource(response, httpClient);
129 | } catch (IOException e) {
130 | log.warn("Close Http Resource error ", e);
131 | }
132 | }
133 | return returnValue;
134 |
135 |
136 | }
137 |
138 |
139 | public static String getContent(String requestUrl) {
140 | return getContent(requestUrl, null);
141 | }
142 |
143 | public static String getHttpsContent(String url) {
144 | CloseableHttpResponse response = null;
145 | String returnValue = null;
146 | CloseableHttpClient httpClient = HttpClientUtil.createSSLClientDefault();
147 | try {
148 | HttpGet get = new HttpGet();
149 | get.setURI(new URI(url));
150 | response = httpClient.execute(get);
151 | returnValue = new String(EntityUtils.toByteArray(response.getEntity()), StandardCharsets.UTF_8);
152 | log.debug(returnValue);
153 | } catch (Exception e) {
154 | log.error("Http Get Content", e);
155 | } finally {
156 | try {
157 | closeHttpResource(response, httpClient);
158 | } catch (IOException e) {
159 | log.warn("Close Http Resource error ", e);
160 | }
161 | }
162 | return returnValue;
163 | }
164 |
165 |
166 | public static String postHttpContent(String url, Map param, Map header) {
167 | CloseableHttpResponse response = null;
168 | String returnValue = null;
169 | CloseableHttpClient httpClient = HttpClientUtil.createSSLClientDefault();
170 | try {
171 | HttpPost post = new HttpPost();
172 | if (header != null && header.size() > 0) {
173 | for (Map.Entry entry : header.entrySet()) {
174 | post.addHeader(entry.getKey(), entry.getValue());
175 | }
176 | }
177 |
178 | List nvps = new ArrayList<>();
179 |
180 | Set keySet = param.keySet();
181 | for (String key : keySet) {
182 | nvps.add(new BasicNameValuePair(key, param.get(key)));
183 | }
184 |
185 | post.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
186 |
187 | post.setURI(new URI(url));
188 | response = httpClient.execute(post);
189 | returnValue = new String(EntityUtils.toByteArray(response.getEntity()), StandardCharsets.UTF_8);
190 | log.debug(returnValue);
191 | } catch (Exception e) {
192 | log.error("Http Post Content", e);
193 | } finally {
194 | try {
195 | closeHttpResource(response, httpClient);
196 | } catch (IOException e) {
197 | log.warn("Close Http Resource error ", e);
198 | }
199 | }
200 | return returnValue;
201 | }
202 |
203 |
204 | public static void closeHttpResource(CloseableHttpResponse response, CloseableHttpClient httpClient)
205 | throws IOException {
206 | if (response != null) {
207 | response.close();
208 | }
209 |
210 | if (httpClient != null) {
211 | httpClient.close();
212 | }
213 | }
214 |
215 | public static CloseableHttpClient createSSLClientDefault() {
216 | try {
217 | SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
218 | @Override
219 | public boolean isTrusted(java.security.cert.X509Certificate[] x509Certificates, String s)
220 | throws java.security.cert.CertificateException {
221 | return false;
222 | }
223 | }).build();
224 | SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
225 | return HttpClients.custom().setSSLSocketFactory(sslsf).build();
226 | } catch (KeyManagementException e) {
227 | e.printStackTrace();
228 | } catch (NoSuchAlgorithmException e) {
229 | e.printStackTrace();
230 | } catch (KeyStoreException e) {
231 | e.printStackTrace();
232 | }
233 | throw new RuntimeException("create ssl error");
234 | }
235 |
236 | }
237 |
--------------------------------------------------------------------------------