From e9bd79b231f89f1d4cd51949fc948fbf0979187f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=A3=95?= <1798488403@qq.com> Date: Fri, 30 Sep 2022 00:47:31 +0800 Subject: [PATCH] code --- src/demo/pom.xml | 56 ++++++++ .../com/example/demo/DemoApplication.java | 5 + .../com/example/demo/common/GlobalResult.java | 107 ++++++++++++++ .../example/demo/common/HttpClientUtil.java | 135 ++++++++++++++++++ .../com/example/demo/common/WechatUtil.java | 78 ++++++++++ .../demo/controller/ControllerText.java | 16 ++- .../demo/controller/UserController.java | 100 +++++++++++++ .../com/example/demo/mapper/UserMapper.java | 13 ++ .../main/java/com/example/demo/pojo/User.java | 78 ++++++++++ src/demo/src/main/resources/application.yaml | 14 +- 10 files changed, 596 insertions(+), 6 deletions(-) create mode 100644 src/demo/src/main/java/com/example/demo/common/GlobalResult.java create mode 100644 src/demo/src/main/java/com/example/demo/common/HttpClientUtil.java create mode 100644 src/demo/src/main/java/com/example/demo/common/WechatUtil.java create mode 100644 src/demo/src/main/java/com/example/demo/controller/UserController.java create mode 100644 src/demo/src/main/java/com/example/demo/mapper/UserMapper.java create mode 100644 src/demo/src/main/java/com/example/demo/pojo/User.java diff --git a/src/demo/pom.xml b/src/demo/pom.xml index e03f479..1f76fa2 100644 --- a/src/demo/pom.xml +++ b/src/demo/pom.xml @@ -27,6 +27,62 @@ spring-boot-starter-test test + + mysql + mysql-connector-java + 5.1.47 + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.apache.httpcomponents + httpclient + 4.5.2 + + + + org.bouncycastle + bcprov-jdk16 + 1.46 + + + + + + org.apache.shiro + shiro-core + 1.4.0 + + + slf4j-api + org.slf4j + + + + + + + com.alibaba + fastjson + 1.2.47 + + + + + org.projectlombok + lombok + true + + + + com.baomidou + mybatis-plus-boot-starter + 3.1.1 + + diff --git a/src/demo/src/main/java/com/example/demo/DemoApplication.java b/src/demo/src/main/java/com/example/demo/DemoApplication.java index 094d95b..fa90a14 100644 --- a/src/demo/src/main/java/com/example/demo/DemoApplication.java +++ b/src/demo/src/main/java/com/example/demo/DemoApplication.java @@ -1,9 +1,14 @@ package com.example.demo; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication +@ComponentScan("com.example.demo.controller") +@MapperScan("com.example.demo.mapper") + public class DemoApplication { public static void main(String[] args) { diff --git a/src/demo/src/main/java/com/example/demo/common/GlobalResult.java b/src/demo/src/main/java/com/example/demo/common/GlobalResult.java new file mode 100644 index 0000000..a66f5e4 --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/common/GlobalResult.java @@ -0,0 +1,107 @@ +package com.example.demo.common; + +/** + * @Description: 自定义响应数据结构 + * 这个类是提供给门户,ios,安卓,微信商城用的 + * 门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list) + * 其他自行处理 + * 200:表示成功 + * 500:表示错误,错误信息在msg字段中 + * 501:bean验证错误,不管多少个错误都以map形式返回 + * 502:拦截器拦截到用户token出错 + * 555:异常抛出信息 + */ +public class GlobalResult { + + // 响应业务状态 + private Integer status; + + // 响应消息 + private String msg; + + // 响应中的数据 + private Object data; + + private String ok; // 不使用 + + public static GlobalResult build(Integer status, String msg, Object data) { + return new GlobalResult(status, msg, data); + } + + public static GlobalResult ok(Object data) { + return new GlobalResult(data); + } + + public static GlobalResult ok() { + return new GlobalResult(null); + } + + public static GlobalResult errorMsg(String msg) { + return new GlobalResult(500, msg, null); + } + + public static GlobalResult errorMap(Object data) { + return new GlobalResult(501, "error", data); + } + + public static GlobalResult errorTokenMsg(String msg) { + return new GlobalResult(502, msg, null); + } + + public static GlobalResult errorException(String msg) { + return new GlobalResult(555, msg, null); + } + + public GlobalResult() { + + } + + public GlobalResult(Integer status, String msg, Object data) { + this.status = status; + this.msg = msg; + this.data = data; + } + + public GlobalResult(Object data) { + this.status = 200; + this.msg = "OK"; + this.data = data; + } + + public Boolean isOK() { + return this.status == 200; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getOk() { + return ok; + } + + public void setOk(String ok) { + this.ok = ok; + } + +} \ No newline at end of file diff --git a/src/demo/src/main/java/com/example/demo/common/HttpClientUtil.java b/src/demo/src/main/java/com/example/demo/common/HttpClientUtil.java new file mode 100644 index 0000000..330a053 --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/common/HttpClientUtil.java @@ -0,0 +1,135 @@ +package com.example.demo.common; + + + +import org.apache.http.NameValuePair; +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.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +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.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HttpClientUtil { + + public static String doGet(String url, Map param) { + + // 创建Httpclient对象 + CloseableHttpClient httpclient = HttpClients.createDefault(); + + String resultString = ""; + CloseableHttpResponse response = null; + try { + // 创建uri + URIBuilder builder = new URIBuilder(url); + if (param != null) { + for (String key : param.keySet()) { + builder.addParameter(key, param.get(key)); + } + } + URI uri = builder.build(); + + // 创建http GET请求 + HttpGet httpGet = new HttpGet(uri); + + // 执行请求 + response = httpclient.execute(httpGet); + // 判断返回状态是否为200 + if (response.getStatusLine().getStatusCode() == 200) { + resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (response != null) { + response.close(); + } + httpclient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return resultString; + } + + public static String doGet(String url) { + return doGet(url, null); + } + + public static String doPost(String url, Map param) { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + // 创建参数列表 + if (param != null) { + List paramList = new ArrayList<>(); + for (String key : param.keySet()) { + paramList.add(new BasicNameValuePair(key, param.get(key))); + } + // 模拟表单 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); + httpPost.setEntity(entity); + } + // 执行http请求 + response = httpClient.execute(httpPost); + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return resultString; + } + + public static String doPost(String url) { + return doPost(url, null); + } + + public static String doPostJson(String url, String json) { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + // 创建请求内容 + StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + // 执行http请求 + response = httpClient.execute(httpPost); + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return resultString; + } +} \ No newline at end of file diff --git a/src/demo/src/main/java/com/example/demo/common/WechatUtil.java b/src/demo/src/main/java/com/example/demo/common/WechatUtil.java new file mode 100644 index 0000000..79d8345 --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/common/WechatUtil.java @@ -0,0 +1,78 @@ +package com.example.demo.common; +;/** + * Create by eval on 2019/3/20 + */ + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.shiro.codec.Base64; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.AlgorithmParameters; +import java.security.Security; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @ClassName WechatUtil + * @Description TODO + * @Author eval + * @Date 9:44 2019/3/20 + * @Version 1.0 + */ +public class WechatUtil { + public static JSONObject getSessionKeyOrOpenId(String code) { + String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; + Map requestUrlParam = new HashMap<>(); + // https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN + //小程序appId + requestUrlParam.put("wx08c675f6ba5b2cdc", "小程序appId"); + //小程序secret + requestUrlParam.put("0c28388c09ff373d391fe66d085dd39d", "小程序secret"); + //小程序端返回的code + requestUrlParam.put("js_code", code); + //默认参数 + requestUrlParam.put("grant_type", "authorization_code"); + //发送post请求读取调用微信接口获取openid用户唯一标识 + JSONObject jsonObject = JSON.parseObject(HttpClientUtil.doPost(requestUrl, requestUrlParam)); + return jsonObject; + } + + public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) { + // 被加密的数据 + byte[] dataByte = Base64.decode(encryptedData); + // 加密秘钥 + byte[] keyByte = Base64.decode(sessionKey); + // 偏移量 + byte[] ivByte = Base64.decode(iv); + try { + // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 + int base = 16; + if (keyByte.length % base != 0) { + int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); + byte[] temp = new byte[groups * base]; + Arrays.fill(temp, (byte) 0); + System.arraycopy(keyByte, 0, temp, 0, keyByte.length); + keyByte = temp; + } + // 初始化 + Security.addProvider(new BouncyCastleProvider()); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); + SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); + AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); + parameters.init(new IvParameterSpec(ivByte)); + cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 + byte[] resultByte = cipher.doFinal(dataByte); + if (null != resultByte && resultByte.length > 0) { + String result = new String(resultByte, "UTF-8"); + return JSON.parseObject(result); + } + } catch (Exception e) { + } + return null; + } +} diff --git a/src/demo/src/main/java/com/example/demo/controller/ControllerText.java b/src/demo/src/main/java/com/example/demo/controller/ControllerText.java index 90ecebe..b7b4852 100644 --- a/src/demo/src/main/java/com/example/demo/controller/ControllerText.java +++ b/src/demo/src/main/java/com/example/demo/controller/ControllerText.java @@ -1,10 +1,12 @@ package com.example.demo.controller; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; - +import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -13,6 +15,7 @@ import java.util.Map; @RestController @SpringBootApplication public class ControllerText { + @RequestMapping("getUser") public Map getUser(){ System.out.println("微信小程序正在调用。。。"); @@ -47,4 +50,15 @@ public class ControllerText { return "hello world"; } + @Autowired + JdbcTemplate jct; + @GetMapping("userslist") + public List> userlist(){ + String sql = "select * from user"; + List> map = jct.queryForList(sql); + System.out.println("调用sql"); + return map; + } + @RequestMapping("hes") + public String get(){return "df";} } diff --git a/src/demo/src/main/java/com/example/demo/controller/UserController.java b/src/demo/src/main/java/com/example/demo/controller/UserController.java new file mode 100644 index 0000000..0b995b3 --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/controller/UserController.java @@ -0,0 +1,100 @@ +package com.example.demo.controller; + + +import com.example.demo.pojo.User; +import com.example.demo.common.GlobalResult; +import com.example.demo.mapper.UserMapper; +import com.example.demo.common.WechatUtil; +//import cn.lastwhisper.springbootwx.common.GlobalResult; +//import cn.lastwhisper.springbootwx.mapper.UserMapper; +//import cn.lastwhisper.springbootwx.pojo.User; +//import cn.lastwhisper.springbootwx.common.WechatUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Date; +import java.util.UUID; + +/** + * @author lastwhisper + * @desc + * @email gaojun56@163.com + */ +@Controller +public class UserController { + + @Autowired + private UserMapper userMapper; + + /** + * 微信用户登录详情 + */ + @PostMapping("wx/login") + @ResponseBody + public GlobalResult user_login(@RequestParam(value = "code", required = false) String code, + @RequestParam(value = "rawData", required = false) String rawData, + @RequestParam(value = "signature", required = false) String signature, + @RequestParam(value = "encrypteData", required = false) String encrypteData, + @RequestParam(value = "iv", required = false) String iv) { + // 用户非敏感信息:rawData + // 签名:signature + JSONObject rawDataJson = JSON.parseObject(rawData); + // 1.接收小程序发送的code + // 2.开发者服务器 登录凭证校验接口 appi + appsecret + code + JSONObject SessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code); + // 3.接收微信接口服务 获取返回的参数 + String openid = SessionKeyOpenId.getString("openid"); + String sessionKey = SessionKeyOpenId.getString("session_key"); + + // 4.校验签名 小程序发送的签名signature与服务器端生成的签名signature2 = sha1(rawData + sessionKey) + String signature2 = DigestUtils.sha1Hex(rawData + sessionKey); + if (!signature.equals(signature2)) { + return GlobalResult.build(500, "签名校验失败", null); + } + // 5.根据返回的User实体类,判断用户是否是新用户,是的话,将用户信息存到数据库;不是的话,更新最新登录时间 + User user = this.userMapper.selectById(openid); + // uuid生成唯一key,用于维护微信小程序用户与服务端的会话 + String skey = UUID.randomUUID().toString(); + if (user == null) { + // 用户信息入库 + String nickName = rawDataJson.getString("nickName"); + String avatarUrl = rawDataJson.getString("avatarUrl"); + String gender = rawDataJson.getString("gender"); + String city = rawDataJson.getString("city"); + String country = rawDataJson.getString("country"); + String province = rawDataJson.getString("province"); + + user = new User(); + user.setOpenId(openid); + user.setSkey(skey); + user.setCreateTime(new Date()); + user.setLastVisitTime(new Date()); + user.setSessionKey(sessionKey); + user.setCity(city); + user.setProvince(province); + user.setCountry(country); + user.setAvatarUrl(avatarUrl); + user.setGender(Integer.parseInt(gender)); + user.setNickName(nickName); + + this.userMapper.insert(user); + } else { + // 已存在,更新用户登录时间 + user.setLastVisitTime(new Date()); + // 重新设置会话skey + user.setSkey(skey); + this.userMapper.updateById(user); + } + //encrypteData比rowData多了appid和openid + //JSONObject userInfo = WechatUtil.getUserInfo(encrypteData, sessionKey, iv); + //6. 把新的skey返回给小程序 + GlobalResult result = GlobalResult.build(200, null, skey); + return result; + } +} diff --git a/src/demo/src/main/java/com/example/demo/mapper/UserMapper.java b/src/demo/src/main/java/com/example/demo/mapper/UserMapper.java new file mode 100644 index 0000000..a9ff07a --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/mapper/UserMapper.java @@ -0,0 +1,13 @@ +package com.example.demo.mapper; + +import com.example.demo.pojo.User; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @desc + * + * @author lastwhisper + * @email gaojun56@163.com + */ +public interface UserMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/demo/src/main/java/com/example/demo/pojo/User.java b/src/demo/src/main/java/com/example/demo/pojo/User.java new file mode 100644 index 0000000..f52df1a --- /dev/null +++ b/src/demo/src/main/java/com/example/demo/pojo/User.java @@ -0,0 +1,78 @@ +package com.example.demo.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author lastwhisper + * @desc + * @email gaojun56@163.com + */ +@Data +@TableName("user") +public class User { + private static final long serialVersionUID = 1L; + /** + * open_id + */ + @TableId(value = "open_id",type = IdType.INPUT) + private String openId; + /** + * skey + */ + private String skey; + /** + * 创建时间 + */ + @TableField("create_time") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date createTime; + /** + * 最后登录时间 + */ + @TableField("last_visit_time") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date lastVisitTime; + /** + * session_key + */ + @TableField("session_key") + private String sessionKey; + /** + * 市 + */ + @TableField("city") + private String city; + /** + * 省 + */ + @TableField("province") + private String province; + /** + * 国 + */ + @TableField("country") + private String country; + /** + * 头像 + */ + @TableField("avatar_url") + private String avatarUrl; + /** + * 性别 + */ + @TableField("gender") + private Integer gender; + /** + * 网名 + */ + @TableField("nick_name") + private String nickName; + +} diff --git a/src/demo/src/main/resources/application.yaml b/src/demo/src/main/resources/application.yaml index 130950f..7c0660a 100644 --- a/src/demo/src/main/resources/application.yaml +++ b/src/demo/src/main/resources/application.yaml @@ -3,8 +3,12 @@ server: spring: - mvc: - view: - prefix=/WEB-INF/jsp/: - suffix=: - jsp: \ No newline at end of file + application: + name: wxlogin + + datasource: + + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false + username: root + password: root \ No newline at end of file