pom.xml jar包
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>weixindemo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>weixindemo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.40</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
Constanst文件
package com.cskt.wxlogin.constanst; public class Constanst { /** * 自定义加密措施 */ public static final String PWD_MD5 = "Cao#@Feng"; }
WeiXinController文件
package com.cskt.wxlogin.controller; import com.cskt.wxlogin.constanst.Constanst; import com.cskt.wxlogin.entity.AccessToken; import com.cskt.wxlogin.entity.WechatUserUnionID; import com.cskt.wxlogin.service.impl.WeixinLoginServiceImpl; import com.cskt.wxlogin.util.AesUtil; import com.cskt.wxlogin.util.DateUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class WeiXinController { @Autowired private WeixinLoginServiceImpl weixinLoginService; @RequestMapping("/weixinLogin") public String getWeixinUrl(){ String url= weixinLoginService.getLoginUrl(); //http return "redirect:"+url; } /** * 回调地址处理 * @param code * @param state * @return */ @GetMapping(value = "/weixinconnect") public ModelAndView callback(String code, String state) { String access_token=null; String openid=null; ModelAndView mav=new ModelAndView(); if (code != null && state != null) { // 验证state为了用于防止跨站请求伪造攻击 String decrypt = AesUtil.decrypt(AesUtil.parseHexStr2Byte(state), AesUtil.PASSWORD_SECRET_KEY, 16); if (!decrypt.equals(Constanst.PWD_MD5 + DateUtil.getYYYYMMdd())) { mav.addObject("error","登录失败,请联系管理员!"); mav.setViewName("loginError"); return mav; } AccessToken access = weixinLoginService.getAccessToken(code); if (access != null) { // 把获取到的access_token和openId赋值给变量 access_token=access.getAccess_token(); openid=access.getOpenid(); // 存在则把当前账号信息授权给扫码用户 WechatUserUnionID userUnionID = weixinLoginService.getUserUnionID(access_token,openid); mav.addObject("userInfo",userUnionID); mav.setViewName("main"); return mav; } } return null; } }
AccessToken文件
package com.cskt.wxlogin.entity; /** * 通过code获取access_token */ public class AccessToken { /** * 接口调用凭证 */ private String access_token; /** * access_token接口调用凭证超时时间,单位(秒) */ private Integer expires_in; /** * 用户刷新access_token */ private String refresh_token; /** * 授权用户唯一标识 */ private String openid; /** * 用户授权的作用域,使用逗号(,)分隔 */ private String scope; /** * 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段。 */ private String unionid; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public Integer getExpires_in() { return expires_in; } public void setExpires_in(Integer expires_in) { this.expires_in = expires_in; } public String getRefresh_token() { return refresh_token; } public void setRefresh_token(String refresh_token) { this.refresh_token = refresh_token; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } }
HttpParame文件
package com.cskt.wxlogin.entity; /** * HttpParame Description: 请求参数 */ public class HttpParame { // 应用唯一标识 public static final String APPID = "appid"; // 密匙 public static final String SECRET = "secret"; // 微信用户唯一标识 public static final String OPENID = "openid"; // 接口调用凭证 public static final String ACCESS_TOKEN = "access_token"; // 回调地址 public static final String REDIRECT_URI = "redirect_uri"; // 网页授权回调地址 public static final String AUTHORIZATION_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"; // 通过code获取access_token public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; // 此接口用于获取用户个人信息 UnionID机制 public static final String GET_UNIONID_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; }
Result文件
package com.cskt.wxlogin.entity; /** * 返回结果包装对象使用 */ public class Result { /** * 状态 */ private Object status; /** * 结果 */ private Object result; /** * 消息 */ private String message; public Result() { } public Result(Object status, String message) { this.status = status; this.message = message; } public Result(Object status, Object result) { this.status = status; this.result = result; } public Result(Object status, Object result, String message) { this.status = status; this.result = result; this.message = message; } public Object getStatus() { return status; } public void setStatus(Object status) { this.status = status; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
WechatUserUnionID文件
package com.cskt.wxlogin.entity; import java.util.List; /** * 获取用户个人信息(UnionID机制) */ public class WechatUserUnionID { /** * 普通用户的标识,对当前开发者帐号唯一 */ private String openid; /** * 普通用户昵称 */ private String nickname; /** * 普通用户性别,1为男性,2为女性 */ private Integer sex; /** * 普通用户个人资料填写的省份 */ private String province; /** * 普通用户个人资料填写的城市 */ private String city; /** * 国家,如中国为CN */ private String country; /** * 用户头像,最后一个数值代表正方形头像大小 (有0、46、64、96、132数值可选,0代表640*640正方形头像) 用户没有头像时该项为空 */ private String headimgurl; /** * 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) */ private List<String> privilege; /** * 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 */ private String unionid; public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } public String getSexStr(){ if (getSex() != null) return getSex() == 1 ? "男" : "女"; return ""; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getHeadimgurl() { return headimgurl; } public void setHeadimgurl(String headimgurl) { this.headimgurl = headimgurl; } public List<String> getPrivilege() { return privilege; } public void setPrivilege(List<String> privilege) { this.privilege = privilege; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } }
WeixinLoginService文件
package com.cskt.wxlogin.service; public interface WeixinLoginService { String getLoginUrl(); }
WeixinLoginServiceImpl文件
package com.cskt.wxlogin.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.cskt.wxlogin.constanst.Constanst; import com.cskt.wxlogin.entity.AccessToken; import com.cskt.wxlogin.entity.HttpParame; import com.cskt.wxlogin.entity.WechatUserUnionID; import com.cskt.wxlogin.service.WeixinLoginService; import com.cskt.wxlogin.util.AesUtil; import com.cskt.wxlogin.util.DateUtil; import com.cskt.wxlogin.util.HttpClientUtil; import com.cskt.wxlogin.util.PropertiesUtil; import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @Service public class WeixinLoginServiceImpl implements WeixinLoginService { @Override public String getLoginUrl() { //第一步 加密 String content = Constanst.PWD_MD5 + DateUtil.getYYYYMMdd(); //第二步 加密密钥 byte[] encrypt = AesUtil.encrypt(content, AesUtil.PASSWORD_SECRET_KEY, 16); //把密钥装成二进制 String parseByte2HexStr = AesUtil.parseByte2HexStr(encrypt); //调取接口 String url = HttpParame.AUTHORIZATION_URL; //输送参数 url = url.replaceAll("APPID", PropertiesUtil.getValue(HttpParame.APPID)); try { //调用回调地址 参数一定要用utf-8 url = url.replaceAll("REDIRECT_URI", URLEncoder.encode( PropertiesUtil.getValue(HttpParame.REDIRECT_URI), "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } url = url.replaceAll("SCOPE", "snsapi_login"); url = url.replace("STATE", parseByte2HexStr); return url; } public AccessToken getAccessToken(String code) { // 调器Code 获取 AccessToken String accessTokenUrl = HttpParame.ACCESS_TOKEN_URL; //带入 appid 和密钥还有code accessTokenUrl = accessTokenUrl.replaceAll("APPID", PropertiesUtil.getValue(HttpParame.APPID)); accessTokenUrl = accessTokenUrl.replaceAll("SECRET", PropertiesUtil.getValue(HttpParame.SECRET)); accessTokenUrl = accessTokenUrl.replaceAll("CODE", code); String responseContent = HttpClientUtil.getInstance().sendHttpGet(accessTokenUrl); if (responseContent == null || responseContent == ""){ return null; } JSONObject parseObject = JSONObject.parseObject(responseContent); AccessToken accessToken = JSONObject.toJavaObject(parseObject, AccessToken.class); return accessToken ; } public WechatUserUnionID getUserUnionID(String access_token, String openid) { //获取用户信息 String unionIDUrl = HttpParame.GET_UNIONID_URL; //根据token获取 用户信息 unionIDUrl = unionIDUrl.replace("ACCESS_TOKEN",access_token); //传入openid unionIDUrl = unionIDUrl.replace("OPENID",openid); //unionIDUrl = unionIDUrl.replace("CITY","上海"); //发送请求 String responseContent = HttpClientUtil.getInstance().sendHttpGet(unionIDUrl); //获取回调参数 System.out.println("responseContent" + responseContent); if (responseContent == null || responseContent == "") { return null; } JSONObject parseObject = JSONObject.parseObject(responseContent); WechatUserUnionID userUnionID = JSONObject.toJavaObject(parseObject, WechatUserUnionID.class); return userUnionID; } }
AesUtil文件
package com.cskt.wxlogin.util; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.UUID; /** * AES加密解密 */ public class AesUtil { public static void main(String[] args) { UUID uuid = UUID.randomUUID(); String content = "token_"+ DateUtil.getYYYYMMdd()+"_"+uuid; System.out.println("内容:"+content); byte[] encrypt = AesUtil.encrypt(content, PASSWORD_SECRET_KEY, 16);//加密 String parseByte2HexStr = AesUtil.parseByte2HexStr(encrypt);//转换为16进制字符串 System.out.println("加密后:"+parseByte2HexStr); byte[] parseHexStr2Byte = AesUtil.parseHexStr2Byte(parseByte2HexStr); String decrypt = AesUtil.decrypt(parseHexStr2Byte, PASSWORD_SECRET_KEY, 16); System.out.println("解密后:"+decrypt); System.out.println("UUID:"+uuid); } /** * 秘钥 */ public static final String PASSWORD_SECRET_KEY = "EasyRailEveryday"; /** * 初始向量 */ public static final String INITIAL_VECTOR = "EasyRailEasyRail"; /** * 加密 * @param content 需要加密的内容 * @param password 加密密码 * @param keySize 密钥长度16,24,32(密码长度为24和32时需要将local_policy.jar/US_export_policy.jar两个jar包放到JRE目录%jre%/lib/security下) * @return */ public static byte[] encrypt(String content, String password, int keySize){ try { //密钥长度不够用0补齐。 SecretKeySpec key = new SecretKeySpec(ZeroPadding(password.getBytes(Base64Util.DEFAULT_CHARSET), keySize), "AES"); //定义加密算法AES、算法模式ECB、补码方式PKCS5Padding //Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); //定义加密算法AES 算法模式CBC、补码方式PKCS5Padding Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //CBC模式模式下初始向量 不足16位用0补齐 IvParameterSpec iv = new IvParameterSpec(ZeroPadding(INITIAL_VECTOR.getBytes(Base64Util.DEFAULT_CHARSET),16)); byte[] byteContent = content.getBytes(); //初始化加密 //ECB //cipher.init(Cipher.ENCRYPT_MODE, key); //CBC cipher.init(Cipher.ENCRYPT_MODE, key,iv); byte[] result = cipher.doFinal(byteContent); return result; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } /**解密 * @param content 待解密内容 * @param password 解密密钥 * @param keySize 密钥长度16,24,32(密码长度为24和32时需要将local_policy.jar/US_export_policy.jar两个jar包放到JRE目录%jre%/lib/security下) * @return */ public static String decrypt(byte[] content, String password, int keySize) { try { //密钥长度不够用0补齐。 SecretKeySpec key = new SecretKeySpec(ZeroPadding(password.getBytes(), keySize), "AES"); //定义加密算法AES、算法模式ECB、补码方式PKCS5Padding //Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); //定义加密算法AES 算法模式CBC、补码方式PKCS5Padding Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //CBC模式模式下初始向量 不足16位用0补齐 IvParameterSpec iv = new IvParameterSpec(ZeroPadding(INITIAL_VECTOR.getBytes(Base64Util.DEFAULT_CHARSET),16)); // 初始化解密 //ECB //cipher.init(Cipher.DECRYPT_MODE, key); //CBC cipher.init(Cipher.DECRYPT_MODE, key,iv); byte[] result = cipher.doFinal(content); return new String(result,Base64Util.DEFAULT_CHARSET); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e){ e.printStackTrace(); } catch (Exception e){ e.printStackTrace(); } return null; } /**将二进制转换成16进制 * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /**将16进制转换为二进制 * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1){ return null; } byte[] result = new byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte) (high * 16 + low); } return result; } /** * 字符达不到指定长度补0 * @param in 字符数组 * @param blockSize 长度 * @return */ public static byte[] ZeroPadding(byte[] in,Integer blockSize){ Integer copyLen = in.length; if (copyLen > blockSize) { copyLen = blockSize; } byte[] out = new byte[blockSize]; System.arraycopy(in, 0, out, 0, copyLen); return out; } }
Base64Util文件
package com.cskt.wxlogin.util; import org.apache.tomcat.util.codec.binary.Base64; import java.nio.charset.Charset; /** * Base64Util工具类 --- 加密和解密 */ public class Base64Util { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); /** * 解密 * @param str * @return */ public static String decodeStr(String str){ if (str == null) { return null; } if (str.length() == 0) { return ""; } return new String(Base64.decodeBase64(new String(str).getBytes(DEFAULT_CHARSET)),DEFAULT_CHARSET).trim(); } /** * 加密 * * @param str * @return */ public static String encodeStr(String str){ if (str == null) { return null; } if (str.length() == 0) { return ""; } return new String(Base64.encodeBase64Chunked(str.getBytes(DEFAULT_CHARSET)),DEFAULT_CHARSET).trim(); } }
DateUtil文件
package com.cskt.wxlogin.util; import org.springframework.stereotype.Component; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * 日期工具类 */ @Component // 加此注解是把此类实例化spring容器中 public class DateUtil { /** * 默认日期格式 */ public static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** * 如2018 0901 232211(年月日时分秒) * * @return */ public String yyyyMMddHHmmss() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如20180901 * * @return */ public static String getYYYYMMdd() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如180901 * @return */ public String getYYMMdd() { SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如201809 * @return */ public String getYYYYMM() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如 2018/02/11 * @return */ public String getQueryEndDate() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如 2018/02/11 * @return */ public String getQueryStartDate() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, -30); return sdf.format(cal.getTime()); } /** * 如 2018/02/11 12:30:00 * @return */ public static String getQueryEndTime() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(Calendar.getInstance().getTime()); } /** * 如 2018/02/11 * @return */ public String getQueryStartTime() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, -30); return sdf.format(cal.getTime()); } public String getQueryTwoAgoDate() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, -2); return sdf.format(cal.getTime()); } /** * 字符串转换成日期 * * @param str 字符串 * @param format 日期格式 * @return 日期 */ public static Date str2Date(String str, String format) { if (null == str || "".equals(str)) { return null; } // 如果没有指定字符串转换的格式,则用默认格式进行转换 if (null == format || "".equals(format)) { format = DEFAULT_FORMAT; } SimpleDateFormat sdf = new SimpleDateFormat(format); Date date = null; try { date = sdf.parse(str); return date; } catch (ParseException e) { } return null; } /** * @param date 日期 * @param format 日期格式 * @return 字符串 */ public static String date2Str(Date date, String format) { if (null == date) { return null; } SimpleDateFormat sdf = new SimpleDateFormat(format); return sdf.format(date); } /** * 时间戳转换为字符串 * @param time * @return */ public static String timestamp2Str(Timestamp time) { Date date = new Date(time.getTime()); return date2Str(date, DEFAULT_FORMAT); } /** * 字符串转换为时间 * @param str * @return */ public static Timestamp str2Timestamp(String str) { Date date = str2Date(str, DEFAULT_FORMAT); return new Timestamp(date.getTime()); } /** * 字符串转换为时间 * @param str * @return */ public static Timestamp str2Timestamp(String str, String formatStr) { if (null == str) { return null; } Date date = str2Date(str, formatStr); return new Timestamp(date.getTime()); } /** * 获取某年第一天日期 * @param year 年份 * @return Date */ public static Date getYearFirst(int year) { Calendar calendar = Calendar.getInstance(); calendar.clear(); calendar.set(Calendar.YEAR, year); Date currYearFirst = calendar.getTime(); return currYearFirst; } /** * 获取某年最后一天日期 * @param year 年份 * @return Date */ public static Date getYearLast(int year) { Calendar calendar = Calendar.getInstance(); calendar.clear(); calendar.set(Calendar.YEAR, year); calendar.roll(Calendar.DAY_OF_YEAR, -1); Date currYearLast = calendar.getTime(); return currYearLast; } @SuppressWarnings("static-access") public static Date getnextLast(String datetime, int year) { Calendar calendar = new GregorianCalendar(); Date date = null; if (datetime.length() > 7) { date = str2Date(datetime, "yyyy-MM-dd"); } else { date = str2Date(datetime, "yyyy-MM"); } calendar.setTime(date); calendar.add(calendar.YEAR, year);// 把日期往后增加一年.整数往后推,负数往前移动 date = calendar.getTime(); return date; } public static String getrightDate(String datetime, int year) { String date = ""; String years = datetime.substring(0, 4); String dates = datetime.substring(4, datetime.length()); Integer s = new Integer(years) + year; date = s + dates; return date; } public static void main(String[] args) { System.out.println(getrightDate("2018-09", 4)); System.out.println(date2Str(getnextLast("2018-09", 4), "yyyy-MM")); } }
HttpClientUtil文件
package com.cskt.wxlogin.util; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.apache.http.conn.util.PublicSuffixMatcher; import org.apache.http.conn.util.PublicSuffixMatcherLoader; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * httpClient 工具类 */ public class HttpClientUtil { /** * 默认参数设置 * setConnectTimeout:设置连接超时时间,单位毫秒。 * setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。 * setSocketTimeout:请求获取数据的超时时间,单位毫秒。访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。 暂时定义15分钟 */ private RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(600000).setConnectTimeout(600000).setConnectionRequestTimeout(600000).build(); /** * 静态内部类---作用:单例产生类的实例 * @author Administrator * */ private static class LazyHolder { private static final HttpClientUtil INSTANCE = new HttpClientUtil(); } private HttpClientUtil(){} public static HttpClientUtil getInstance(){ return LazyHolder.INSTANCE; } /** * 发送 post请求 * @param httpUrl 地址 */ public String sendHttpPost(String httpUrl) { HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost return sendHttpPost(httpPost); } /** * 发送 post请求 * @param httpUrl 地址 * @param params 参数(格式:key1=value1&key2=value2) */ public String sendHttpPost(String httpUrl, String params) { HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost try { //设置参数 StringEntity stringEntity = new StringEntity(params, "UTF-8"); stringEntity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(stringEntity); } catch (Exception e) { e.printStackTrace(); } return sendHttpPost(httpPost); } /** * 发送 post请求 * @param httpUrl 地址 * @param maps 参数 */ public String sendHttpPost(String httpUrl, Map<String, String> maps) { HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost // 创建参数队列 List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); for (String key : maps.keySet()) { nameValuePairs.add(new BasicNameValuePair(key, maps.get(key))); } try { httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8")); } catch (Exception e) { e.printStackTrace(); } return sendHttpPost(httpPost); } /** * 发送Post请求 * @param httpPost * @return */ private String sendHttpPost(HttpPost httpPost) { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; HttpEntity entity = null; String responseContent = null; try { // 创建默认的httpClient实例 httpClient = HttpClients.createDefault(); httpPost.setConfig(requestConfig); // 执行请求 long execStart = System.currentTimeMillis(); response = httpClient.execute(httpPost); long execEnd = System.currentTimeMillis(); System.out.println("=================执行post请求耗时:"+(execEnd-execStart)+"ms"); long getStart = System.currentTimeMillis(); entity = response.getEntity(); responseContent = EntityUtils.toString(entity, "UTF-8"); long getEnd = System.currentTimeMillis(); System.out.println("=================获取响应结果耗时:"+(getEnd-getStart)+"ms"); } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭连接,释放资源 if (response != null) { response.close(); } if (httpClient != null) { httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } return responseContent; } /** * 发送 get请求 * @param httpUrl */ public String sendHttpGet(String httpUrl) { HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 return sendHttpGet(httpGet); } /** * 发送 get请求Https * @param httpUrl */ public String sendHttpsGet(String httpUrl) { HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 return sendHttpsGet(httpGet); } /** * 发送Get请求 * @param httpPost * @return */ private String sendHttpGet(HttpGet httpGet) { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; HttpEntity entity = null; String responseContent = null; try { // 创建默认的httpClient实例. httpClient = HttpClients.createDefault(); httpGet.setConfig(requestConfig); // 执行请求 response = httpClient.execute(httpGet); entity = response.getEntity(); responseContent = EntityUtils.toString(entity, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭连接,释放资源 if (response != null) { response.close(); } if (httpClient != null) { httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } return responseContent; } /** * 发送Get请求Https * @param httpPost * @return */ private String sendHttpsGet(HttpGet httpGet) { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; HttpEntity entity = null; String responseContent = null; try { // 创建默认的httpClient实例. PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(new URL(httpGet.getURI().toString())); DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher); httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build(); httpGet.setConfig(requestConfig); // 执行请求 response = httpClient.execute(httpGet); entity = response.getEntity(); responseContent = EntityUtils.toString(entity, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭连接,释放资源 if (response != null) { response.close(); } if (httpClient != null) { httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } return responseContent; } }
PropertiesUtil文件
package com.cskt.wxlogin.util; import java.io.*; import java.net.URI; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * properties资源文件解析工具 */ public class PropertiesUtil { private static Properties props = null; private static URI uri; private static String fileName = "/weixinconnectconfig.properties"; private static InputStream in = null; static { try { props = new Properties(); InputStream fis = PropertiesUtil.class.getResourceAsStream(fileName); props.load(fis); uri = PropertiesUtil.class.getResource(fileName).toURI(); } catch (Exception e) { e.printStackTrace(); } } /** * 获取某个属性 */ public static String getProperty(String key) { try { props.load(PropertiesUtil.class.getResourceAsStream(fileName)); } catch (IOException e) { e.printStackTrace(); } return props.getProperty(key); } /** * 获取所有属性,返回一个map,不常用 可以试试props.putAll(t) */ @SuppressWarnings("rawtypes") public static Map<String, String> getAllProperty() { Map<String, String> map = new HashMap<String, String>(); Enumeration enu = props.propertyNames(); while (enu.hasMoreElements()) { String key = (String) enu.nextElement(); String value = props.getProperty(key); map.put(key, value); } return map; } /** * 在控制台上打印出所有属性,调试时用。 */ public static void printProperties() { props.list(System.out); } /** * 写入properties信息 */ public static void writeProperties(String key, String value) { try { OutputStream fos = new FileOutputStream(new File(uri)); props.setProperty(key, value); // 将此 Properties 表中的属性列表(键和元素对)写入输出流 props.store(fos, "『comments』Update key:" + key); } catch (Exception e) { e.printStackTrace(); } } /** * 取默认key的value * */ public static String getValue(String key){ String value = null; props = new Properties(); in = PropertiesUtil.class.getResourceAsStream(fileName); try { props.load(in); } catch (IOException e) { // e.printStackTrace(); } value = (String) props.get(key); return value; } }
application.yml配置文件
server: port: 80 spring: thymeleaf: mode: HTML5 prefix: classpath:/templates/ suffix: .html cache: false
weixinconnectconfig.properties配置文件
appid=wx9dbc36f6430dc621
secret=11f48317f08fe2afbdf5cb80dcc4e99d
redirect_uri=http://www.csktedu.com/weixinconnect
templates文件夹
index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title th:text="${title}"></title> </head> <body> <div style="padding: 40px"> <font color="black"><strong>微信扫码登录测试</strong></font><br/><br/><a href="/weixinLogin"><img src="/images/weixinlogin.png"/></a> </div> </body> </html>
main
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <div style="padding: 20px"> <p>微信唯一标识OpenId: <font th:text="${userInfo.openid}"></font></p> <p>昵称: <font th:text="${userInfo.nickname}"></font></p> <p>性别: <font th:text="${userInfo.sexStr}"></font></p> <p><img th:src="${userInfo.headimgurl}"/></p> </div> ooxx </body> </html>