前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo)
作者:mmseoamin日期:2024-01-18

实现微信小程序授权登录

      • 1、前端技术栈
        • 1.1、uniapp
        • 1.2、前端封装工具
        • 1.3、Hbuilderx构建uniapp项目
        • 2、后端技术栈
          • 2.1、创建springboot后端项目
          • 2.2、数据库准备
          • 2.3、创建实体类
          • 2.4、后端工具类
          • 2.5、mapper和service接口
          • 2.5、Service实现类
          • 2.6、微信用户的控制层Controller

            微信小程序官方登录流程图:

            前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo),在这里插入图片描述,第1张

            参考微信小程序登录官网文档

            1、前端技术栈

            1.1、uniapp

            使用uniapp构建一套代码多端使用的前端框架项目

            1.2、前端封装工具
            • dateUtil.js:

              功能:

              1. 时间日期格式化

              2. 传入日期是否和当前日期的比较

              完整代码:

              // 判断传入日期是否和当前日期比较 
               const judgeDate=(toDate)=>{
              	return new Date().getTime()-new Date(toDate).getTime();
              }
              var timeFormat = function (msTime) {
                  let time = new Date(msTime);
                  let yy = time.getFullYear();
                  let MM = time.getMonth() + 1;
                  let dd = time.getDate();
                  let hh = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();
                  let min =
                      time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
                  let sec =
                      time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
                  return yy + "-" + MM + "-" + dd + " " + hh + ":" + min + ":" + sec;
              }
              export {timeFormat,judgeDate}
              
            • requestUtil.js:

              功能:

              1. 定义公共的url

              2. 后端请求工具封装

              完整代码:

              // 同时发送异步代码的次数
              let ajaxTimes = 0;
              // 定义公共的url
              const baseUrl = "http://localhost:8866";
              /**
               * 返回baseUrl
               */
              export const getBaseUrl = () => {
                return baseUrl;
              }
              /**
               * 后端请求工具类
               * @param {*} params 请求参数
               */
              export const requestUtil = (params) => {
                let header = {
                  ...params.header
                };
                // 拼接header 带上token
                header["token"] = uni.getStorageSync("token");
                ajaxTimes++;
                // 显示加载中 效果
                wx.showLoading({
                  title: "加载中",
                  mask: true
                });
                var start = new Date().getTime();
                // 模拟网络延迟加载
                while (true)
                  if (new Date().getTime() - start > 1000 * 1) break;
                return new Promise((resolve, reject) => {
                  wx.request({
                    ...params,
                    header: header,
                    url: baseUrl + params.url,
                    success: (result) => {
                      resolve(result.data);
                    },
                    fail: (err) => {
                      uni.showToast({
                        icon: 'error',
                        title: '连接服务器失败',
                        duration: 3000
                      })
                      reject(err);
                    },
                    complete: () => {
                      ajaxTimes--;
                      if (ajaxTimes === 0) {
                        //  关闭正在等待的图标
                        wx.hideLoading();
                      }
                    }
                  });
                })
              }
              
            • stringUtil.js:

              功能:

              1. 判断字符串是否为空

              完整代码:

              //判断字符串是否为空
              export const isEmpty = (str) => {
                if (str === '' || str.trim().length === 0) {
                  return true
                } else {
                  return false;
                }
              }
              
              1.3、Hbuilderx构建uniapp项目

              前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo),在这里插入图片描述,第2张

              项目结构:

              前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo),在这里插入图片描述,第3张

              app.vue中,写两个方法:

              1. 在onLaunch生命周期函数中调用wx.login()获取code(前提是在微信开发者工具中登录微信账号,而且在uniapp中设置微信小程序AppId),code的作用是后端接受到code,通过code参数向微信后台发送请求,它是实现微信临时登录的url中的一个非常重要的参数。
              2. 三个重要参数
              • appid:应用ID
              • secret:应用密钥
              • js_code:前台传给我们的code
                1. wxlogin方法

                  携带code参数发送请求给后端来获取token和openid

                
                

                2、后端技术栈

                • springboot后端技术框架
                • mybatis-plus数据持久层框架
                  2.1、创建springboot后端项目

                  利用idea工具,使用spring initializr初始化创建一个空的springboot项目

                  springboot版本选择2.3.2.RELEASE。

                  1. 修改pom.xml
                   
                          
                              org.springframework.boot
                              spring-boot-starter-web
                          
                          
                              org.springframework.boot
                              spring-boot-starter-test
                              test
                          
                          
                              org.springframework.boot
                              spring-boot-starter-validation
                          
                          
                              org.springframework.boot
                              spring-boot-devtools
                              runtime
                              true
                          
                          
                              mysql
                              mysql-connector-java
                              runtime
                          
                          
                          
                              com.alibaba
                              druid
                              1.1.10
                          
                          
                          
                              com.baomidou
                              mybatis-plus-boot-starter
                              3.3.2
                          
                          
                              com.alibaba
                              fastjson
                              1.2.40
                          
                          
                          
                              com.auth0
                              java-jwt
                              3.2.0
                          
                          
                              io.jsonwebtoken
                              jjwt
                              0.9.1
                          
                          
                              commons-io
                              commons-io
                              2.5
                          
                          
                              org.projectlombok
                              lombok
                              true
                          
                          
                          
                              org.springframework.boot
                              spring-boot-starter-data-redis
                          
                          
                          
                              org.apache.commons
                              commons-pool2
                          
                          
                          
                              cn.hutool
                              hutool-all
                              5.3.3
                          
                          
                          
                              com.github.axet
                              kaptcha
                              0.0.9
                          
                          
                          
                              org.apache.httpcomponents
                              httpclient
                              4.5.2
                          
                      
                      
                          
                              
                                  org.springframework.boot
                                  spring-boot-maven-plugin
                                  2.3.2.RELEASE
                              
                          
                      
                  
                  1. 创建application.yml
                  server:
                    port: 8866
                    servlet:
                      context-path: /
                  spring:
                    datasource:
                      type: com.alibaba.druid.pool.DruidDataSource
                      driver-class-name: com.mysql.cj.jdbc.Driver
                      url: jdbc:mysql://localhost:3306/db-wxlogin?serverTimezone=Asia/Shanghai
                      username: root
                      password: 123456
                  mybatis-plus:
                    global-config:
                      db-config:
                        id-type: auto
                    configuration:
                      map-underscore-to-camel-case: true
                      auto-mapping-behavior: full
                      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
                    mapper-locations: classpath:mapper/*.xml
                  weixin:
                    jscode2sessionUrl: https://api.weixin.qq.com/sns/jscode2session
                    appid: wxa4aa78831ea93858  #修改自己的微信小程序 appId
                    secret: a2efb3b611d96b2dee615b7a4dee451a   #修改自己的微信小程序 appSecret
                  
                  2.2、数据库准备

                  创建名称db-wxlogin的数据库

                  创建t_wxuserinfo数据表
                  
                  CREATE TABLE `t_wxuserinfo` (
                    `id` int NOT NULL AUTO_INCREMENT COMMENT '用户编号',
                    `openid` varchar(30) DEFAULT NULL COMMENT '用户唯一标识',
                    `nick_name` varchar(50) DEFAULT NULL COMMENT '用户昵称',
                    `avatar_url` varchar(200) DEFAULT NULL COMMENT '用户头像图片的 URL',
                    `register_date` datetime DEFAULT NULL COMMENT '注册日期',
                    `last_login_date` datetime DEFAULT NULL COMMENT '最后登录日期',
                    `status` char(1) DEFAULT '1' COMMENT '状态 0 可用 1 封禁',
                    PRIMARY KEY (`id`)
                  ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
                  
                  2.3、创建实体类
                  • WxUserInfo类

                    对应数据库表t_wxuserinfo

                    package com.tigerhhzz.springbootvote.entity;
                    import com.baomidou.mybatisplus.annotation.TableField;
                    import com.baomidou.mybatisplus.annotation.TableName;
                    import com.fasterxml.jackson.databind.annotation.JsonSerialize;
                    import lombok.Data;
                    import java.io.Serializable;
                    import java.util.Date;
                    /**
                     * 微信用户信息实体
                     *
                     * @author tigerhhzz
                     * @date 2023/5/17 15:34
                     */
                    @TableName("t_wxUserInfo")
                    @Data
                    public class WxUserInfo implements Serializable {
                        private Integer id; // 用户编号
                        private String openid; // 用户唯一标识
                        private String nickName="微信用户"; // 用户昵称
                        private String avatarUrl="default.png"; // 用户头像图片的 URL
                        @JsonSerialize(using=CustomDateTimeSerializer.class)
                        private Date registerDate; // 注册日期
                        @JsonSerialize(using=CustomDateTimeSerializer.class)
                        private Date lastLoginDate; // 最后登录日期
                        private String status="0"; // 用户状态 状态 0 可用 1 封禁
                        //查询时,则不返回该字段的值    设置该字段在数据库表中不存在
                        @TableField(select = false,exist = false)
                        private String code; // 微信用户code 前端传来的
                    }
                    
                    • 页面响应实体类
                      package com.tigerhhzz.springbootvote.entity;
                      import java.util.HashMap;
                      import java.util.Map;
                      /**
                       * 页面响应entity
                       *
                       * @author tigerhhzz
                       * @date 2023/5/17 15:34
                       */
                      public class R extends HashMap {
                          private static final long serialVersionUID = 1L;
                          public R() {
                              put("code", 0);
                          }
                          public static R error() {
                              return error(500, "未知异常,请联系管理员");
                          }
                          public static R error(String msg) {
                              return error(500, msg);
                          }
                          public static R error(int code, String msg) {
                              R r = new R();
                              r.put("code", code);
                              r.put("msg", msg);
                              return r;
                          }
                          public static R ok(String msg) {
                              R r = new R();
                              r.put("msg", msg);
                              return r;
                          }
                          public static R ok(Map map) {
                              R r = new R();
                              r.putAll(map);
                              return r;
                          }
                          public static R ok() {
                              return new R();
                          }
                          @Override
                          public R put(String key, Object value) {
                              super.put(key, value);
                              return this;
                          }
                      }
                      
                      • jwt验证信息
                        package com.tigerhhzz.springbootvote.entity;
                        import io.jsonwebtoken.Claims;
                        /**
                         * jwt验证信息
                         *
                         * @author tigerhhzz
                         * @date 2023/5/17 17:05
                         */
                        public class CheckResult {
                            private int errCode;
                            private boolean success;
                            private Claims claims;
                            public int getErrCode() {
                                return errCode;
                            }
                            public void setErrCode(int errCode) {
                                this.errCode = errCode;
                            }
                            public boolean isSuccess() {
                                return success;
                            }
                            public void setSuccess(boolean success) {
                                this.success = success;
                            }
                            public Claims getClaims() {
                                return claims;
                            }
                            public void setClaims(Claims claims) {
                                this.claims = claims;
                            }
                        }
                        
                        • 微信小程序配置文件
                          package com.tigerhhzz.springbootvote.properties;
                          import lombok.Data;
                          import org.springframework.boot.context.properties.ConfigurationProperties;
                          import org.springframework.stereotype.Component;
                          /**
                           * 微信小程序配置文件
                           *
                           * @author tigerhhzz
                           * @date 2023/5/17 16:55
                           */
                          @Component
                          @ConfigurationProperties(prefix = "weixin")
                          @Data
                          public class WeixinProperties {
                              private String jscode2sessionUrl; // 登录凭证校验请求地址
                              private String appid; // 小程序 appId
                              private String secret; // 小程序 appSecret
                          }
                          
                          2.4、后端工具类
                          • 日期工具类 DateUtil
                            package com.tigerhhzz.springbootvote.util;
                            import java.text.SimpleDateFormat;
                            import java.util.Date;
                            /**
                             * 日期工具类
                             *
                             * @author tigerhhzz
                             * @date 2023/5/17 15:34
                             */
                            public class DateUtil {
                            	/**
                            	 * 日期对象转字符串
                            	 * @param date
                            	 * @param format
                            	 * @return
                            	 */
                            	public static String formatDate(Date date,String format){
                            		String result="";
                            		SimpleDateFormat sdf=new SimpleDateFormat(format);
                            		if(date!=null){
                            			result=sdf.format(date);
                            		}
                            		return result;
                            	}
                            	
                            	/**
                            	 * 字符串转日期对象
                            	 * @param str
                            	 * @param format
                            	 * @return
                            	 * @throws Exception
                            	 */
                            	public static Date formatString(String str,String format) throws Exception{
                            		if(StringUtil.isEmpty(str)){
                            			return null;
                            		}
                            		SimpleDateFormat sdf=new SimpleDateFormat(format);
                            		return sdf.parse(str);
                            	}
                            	
                            	public static String getCurrentDateStr(){
                            		Date date=new Date();
                            		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddhhmmssSSSSSSSSS");
                            		return sdf.format(date);
                            	}
                            	
                            	public static String getCurrentDatePath()throws Exception{
                            		Date date=new Date();
                            		SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
                            		return sdf.format(date);
                            	}
                            	
                            	public static void main(String[] args) {
                            		try {
                            			System.out.println(getCurrentDateStr());
                            		} catch (Exception e) {
                            			// TODO Auto-generated catch block
                            			e.printStackTrace();
                            		}
                            	}
                            }
                            
                            • httpClient 工具类
                              package com.tigerhhzz.springbootvote.util;
                              import org.apache.http.HttpEntity;
                              import org.apache.http.HttpResponse;
                              import org.apache.http.NameValuePair;
                              import org.apache.http.client.ClientProtocolException;
                              import org.apache.http.client.HttpClient;
                              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 org.springframework.stereotype.Component;
                              import java.io.*;
                              import java.net.URL;
                              import java.util.ArrayList;
                              import java.util.List;
                              import java.util.Map;
                              /**
                               * httpClient 工具类
                               *
                               * @author tigerhhzz
                               * @date 2023/5/17 15:34
                               */
                              @Component
                              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 maps) {
                              		HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost  
                              		// 创建参数队列  
                              		List nameValuePairs = new ArrayList();
                              		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 httpGet
                              	 * @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 httpGet
                              	 * @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;
                              	}
                              	/**
                              	 * 发送xml数据
                              	 * @param url
                              	 * @param xmlData
                              	 * @return
                              	 * @throws ClientProtocolException
                              	 * @throws IOException
                              	 */
                              	public static HttpResponse sendXMLDataByPost(String url, String xmlData)
                              			throws ClientProtocolException, IOException {
                              		HttpClient httpClient = HttpClients.createDefault();
                              		HttpPost httppost = new HttpPost(url);
                              		StringEntity entity = new StringEntity(xmlData);
                              		httppost.setEntity(entity);
                              		httppost.setHeader("Content-Type", "text/xml;charset=UTF-8");
                              		HttpResponse response = httpClient.execute(httppost);
                              		return response;
                              	}
                              	/**
                              	 * 获得响应HTTP实体内容
                              	 *
                              	 * @param response
                              	 * @return
                              	 * @throws IOException
                              	 * @throws UnsupportedEncodingException
                              	 */
                              	public static String getHttpEntityContent(HttpResponse response) throws IOException, UnsupportedEncodingException {
                              		HttpEntity entity = response.getEntity();
                              		if (entity != null) {
                              			InputStream is = entity.getContent();
                              			BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                              			String line = br.readLine();
                              			StringBuilder sb = new StringBuilder();
                              			while (line != null) {
                              				sb.append(line + "\n");
                              				line = br.readLine();
                              			}
                              			return sb.toString();
                              		}
                              		return "";
                              	}
                              }
                              
                              • jwt加密和解密的工具类
                                package com.tigerhhzz.springbootvote.util;
                                import com.tigerhhzz.springbootvote.constant.JwtConstant;
                                import com.tigerhhzz.springbootvote.entity.CheckResult;
                                import io.jsonwebtoken.*;
                                import org.bouncycastle.util.encoders.Base64;
                                import javax.crypto.SecretKey;
                                import javax.crypto.spec.SecretKeySpec;
                                import java.util.Date;
                                /**
                                 * jwt加密和解密的工具类
                                 *
                                 * @author tigerhhzz
                                 * @date 2023/5/17 15:34
                                 */
                                public class JwtUtils {
                                    /**
                                     * 签发JWT
                                     * @param id
                                     * @param subject 可以是JSON数据 尽可能少
                                     * @param ttlMillis
                                     * @return
                                     */
                                    public static String createJWT(String id, String subject, long ttlMillis) {
                                        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
                                        long nowMillis = System.currentTimeMillis();
                                        Date now = new Date(nowMillis);
                                        SecretKey secretKey = generalKey();
                                        JwtBuilder builder = Jwts.builder()
                                                .setId(id)
                                                .setSubject(subject)   // 主题
                                                .setIssuer("tigerhhzz")     // 签发者
                                                .setIssuedAt(now)      // 签发时间
                                                .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
                                        if (ttlMillis >= 0) {
                                            long expMillis = nowMillis + ttlMillis;
                                            Date expDate = new Date(expMillis);
                                            builder.setExpiration(expDate); // 过期时间
                                        }
                                        return builder.compact();
                                    }
                                    /**
                                     * 生成jwt token
                                     * @param username
                                     * @return
                                     */
                                    public static String genJwtToken(String username){
                                        return createJWT(username,username,60*60*1000);
                                    }
                                    /**
                                     * 验证JWT
                                     * @param jwtStr
                                     * @return
                                     */
                                    public static CheckResult validateJWT(String jwtStr) {
                                        CheckResult checkResult = new CheckResult();
                                        Claims claims = null;
                                        try {
                                            claims = parseJWT(jwtStr);
                                            checkResult.setSuccess(true);
                                            checkResult.setClaims(claims);
                                        } catch (ExpiredJwtException e) {
                                            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_EXPIRE);
                                            checkResult.setSuccess(false);
                                        } catch (SignatureException e) {
                                            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);
                                            checkResult.setSuccess(false);
                                        } catch (Exception e) {
                                            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);
                                            checkResult.setSuccess(false);
                                        }
                                        return checkResult;
                                    }
                                    /**
                                     * 生成加密Key
                                     * @return
                                     */
                                    public static SecretKey generalKey() {
                                        byte[] encodedKey = Base64.decode(JwtConstant.JWT_SECERT);
                                        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
                                        return key;
                                    }
                                    /**
                                     * 解析JWT字符串
                                     * @param jwt
                                     * @return
                                     * @throws Exception
                                     */
                                    public static Claims parseJWT(String jwt) {
                                        SecretKey secretKey = generalKey();
                                        return Jwts.parser()
                                                .setSigningKey(secretKey)
                                                .parseClaimsJws(jwt)
                                                .getBody();
                                    }
                                    public static void main(String[] args) throws InterruptedException {
                                        //小明失效 10s
                                        String sc = createJWT("1","小明", 60 * 60 * 1000);
                                        System.out.println(sc);
                                        System.out.println(validateJWT(sc).getErrCode());
                                        System.out.println(validateJWT(sc).getClaims().getId());
                                        System.out.println(validateJWT(sc).getClaims().getSubject());
                                        //Thread.sleep(3000);
                                        System.out.println(validateJWT(sc).getClaims());
                                        Claims claims = validateJWT(sc).getClaims();
                                        String sc2 = createJWT(claims.getId(),claims.getSubject(), JwtConstant.JWT_TTL);
                                        System.out.println(sc2);
                                    }
                                }
                                
                                • 字符串工具类
                                  package com.tigerhhzz.springbootvote.util;
                                  import java.util.ArrayList;
                                  import java.util.List;
                                  import java.util.Random;
                                  /**
                                   * 字符串工具类
                                   * @author 
                                   *
                                   */
                                  public class StringUtil {
                                  	/**
                                  	 * 判断是否是空
                                  	 * @param str
                                  	 * @return
                                  	 */
                                  	public static boolean isEmpty(String str){
                                  		if(str==null||"".equals(str.trim())){
                                  			return true;
                                  		}else{
                                  			return false;
                                  		}
                                  	}
                                  	
                                  	/**
                                  	 * 判断是否不是空
                                  	 * @param str
                                  	 * @return
                                  	 */
                                  	public static boolean isNotEmpty(String str){
                                  		if((str!=null)&&!"".equals(str.trim())){
                                  			return true;
                                  		}else{
                                  			return false;
                                  		}
                                  	}
                                  	
                                  	/**
                                  	 * 格式化模糊查询
                                  	 * @param str
                                  	 * @return
                                  	 */
                                  	public static String formatLike(String str){
                                  		if(isNotEmpty(str)){
                                  			return "%"+str+"%";
                                  		}else{
                                  			return null;
                                  		}
                                  	}
                                  	
                                  	/**
                                  	 * 过滤掉集合里的空格
                                  	 * @param list
                                  	 * @return
                                  	 */
                                  	public static List filterWhite(List list){
                                  		List resultList=new ArrayList();
                                  		for(String l:list){
                                  			if(isNotEmpty(l)){
                                  				resultList.add(l);
                                  			}
                                  		}
                                  		return resultList;
                                  	}
                                  	
                                  	/**
                                  	 * 去除html标签
                                  	 */
                                  	public static String stripHtml(String content) { 
                                  	    // 

                                  段落替换为换行 content = content.replaceAll("

                                  ", "\r\n"); //

                                  替换为换行 content = content.replaceAll("", "\r\n"); // 去掉其它的<>之间的东西 content = content.replaceAll("\\<.*?>", ""); // 去掉空格 content = content.replaceAll(" ", ""); return content; } /** * 生成六位随机数 * @return */ public static String genSixRandomNum(){ Random random = new Random(); String result=""; for (int i=0;i<6;i++) { result+=random.nextInt(10); } return result; } /** * 生成由[A-Z,0-9]生成的随机字符串 * @param length 欲生成的字符串长度 * @return */ public static String getRandomString(int length){ Random random = new Random(); StringBuffer sb = new StringBuffer(); for(int i = 0; i < length; ++i){ int number = random.nextInt(2); long result = 0; switch(number){ case 0: result = Math.round(Math.random() * 25 + 65); sb.append(String.valueOf((char)result)); break; case 1: sb.append(String.valueOf(new Random().nextInt(10))); break; } } return sb.toString(); } }

                                  2.5、mapper和service接口

                                  微信用户mapper —WxUserInfoMapper

                                  package com.tigerhhzz.springbootvote.mapper;
                                  import com.baomidou.mybatisplus.core.mapper.BaseMapper;
                                  import com.tigerhhzz.springbootvote.entity.WxUserInfo;
                                  import org.springframework.stereotype.Repository;
                                  /**
                                   * 微信用户mapper
                                   *
                                   * @author tigerhhzz
                                   * @date 2023/5/17 15:26
                                   */
                                  @Repository
                                  public interface WxUserInfoMapper extends BaseMapper {
                                  }
                                  

                                  微信用户Service接口 —WxUserInfoService

                                  package com.tigerhhzz.springbootvote.service;
                                  import com.baomidou.mybatisplus.extension.service.IService;
                                  import com.tigerhhzz.springbootvote.entity.WxUserInfo;
                                  /**
                                   * 微信用户Service接口
                                   *
                                   * @author tigerhhzz
                                   * @date 2023/5/17 15:34
                                   */
                                  public interface WxUserInfoService extends IService {
                                  }
                                  
                                  2.5、Service实现类

                                  WxUserInfoServiceImpl---- 实现WxUserInfoService 接口,并继承ServiceImpl实现类的泛型WxUserInfoMapper和WxUserInfo。

                                  package com.tigerhhzz.springbootvote.service.impl;
                                  import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
                                  import com.tigerhhzz.springbootvote.entity.WxUserInfo;
                                  import com.tigerhhzz.springbootvote.mapper.WxUserInfoMapper;
                                  import com.tigerhhzz.springbootvote.service.WxUserInfoService;
                                  import org.springframework.stereotype.Service;
                                  /**
                                   * 微信用户Service实现类
                                   *
                                   * @author tigerhhzz
                                   * @date 2023/5/17 15:34
                                   */
                                  @Service //("wxUserInfoService")
                                  public class WxUserInfoServiceImpl extends ServiceImpl implements WxUserInfoService {
                                      //@Autowired
                                      //private WxUserInfoMapper wxUserInfoMapper;
                                  }
                                  
                                  2.6、微信用户的控制层Controller

                                  两个控制层请求接口

                                  1. /user/wxlogin

                                  功能: 通过前端发送请求携带的参数code以及后端配置文件中的微信小程序appid和微信小程序密钥,后端拼接url向微信后台发送请求。

                                  		 String jscode2sessionUrl=weixinProperties.getJscode2sessionUrl()+"?appid="+weixinProperties.getAppid()+"&secret="+weixinProperties.getSecret()+"&js_code="+wxUserInfo.getCode()+"&grant_type=authorization_code";
                                  		// https://api.weixin.qq.com/sns/jscode2session?appid=wxa4de78832ea93858&secret=a2efb3b602d96b2dee615b7a4dee451a&js_code=0b1JwPkl2xqHkb4VEjml2vVdua3JwPkq&grant_type=authorization_code
                                  
                                          //后端向微信后台送发请求 获取openid
                                          String result = httpClientUtil.sendHttpGet(jscode2sessionUrl);
                                          System.out.println(result); 
                                          //结果:{"session_key":"TPTXzC9MOe1owBJ8zrSWTw==","openid":"o2yqx5PBEW-ezFHA24ASqP0Lk1M0"}
                                  

                                  通过拿到的openid,去数据库查询对应用户信息,如果没有openid的用户,进行新增操作;

                                  如果存在openid的用户,进行更新操作。

                                  最后利用jwt工具类生成token,返回前端

                                   // 利用jwt生成token返回到前端
                                    String token = JwtUtils.createJWT(openid, wxUserInfo.getNickName(), JwtConstant.JWT_TTL);
                                  
                                    Map resultMap=new HashMap<>();
                                    resultMap.put("token",token);
                                    resultMap.put("openid",openid);
                                    return R.ok(resultMap);
                                  
                                  1. /user/getUserInfo

                                  功能: 通过前端发送请求,请求头中携带token参数,后端接受到token,然后进行token验证,拿到openid,通过openid去数据库中查询用户信息,并返回前端

                                  //token验证
                                  Claims claims = JwtUtils.validateJWT(token).getClaims();
                                  

                                  获取当前微信登录用户信息:

                                  前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo),在这里插入图片描述,第4张


                                  WeixinUserController 完整代码:

                                  package com.tigerhhzz.springbootvote.controller;
                                  import com.alibaba.fastjson.JSON;
                                  import com.alibaba.fastjson.JSONObject;
                                  import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
                                  import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
                                  import com.tigerhhzz.springbootvote.constant.JwtConstant;
                                  import com.tigerhhzz.springbootvote.entity.R;
                                  import com.tigerhhzz.springbootvote.entity.WxUserInfo;
                                  import com.tigerhhzz.springbootvote.properties.WeixinProperties;
                                  import com.tigerhhzz.springbootvote.service.WxUserInfoService;
                                  import com.tigerhhzz.springbootvote.util.DateUtil;
                                  import com.tigerhhzz.springbootvote.util.HttpClientUtil;
                                  import com.tigerhhzz.springbootvote.util.JwtUtils;
                                  import com.tigerhhzz.springbootvote.util.StringUtil;
                                  import io.jsonwebtoken.Claims;
                                  import org.apache.commons.io.FileUtils;
                                  import org.springframework.beans.factory.annotation.Autowired;
                                  import org.springframework.beans.factory.annotation.Value;
                                  import org.springframework.web.bind.annotation.RequestBody;
                                  import org.springframework.web.bind.annotation.RequestHeader;
                                  import org.springframework.web.bind.annotation.RequestMapping;
                                  import org.springframework.web.bind.annotation.RestController;
                                  import org.springframework.web.multipart.MultipartFile;
                                  import java.io.File;
                                  import java.util.Date;
                                  import java.util.HashMap;
                                  import java.util.List;
                                  import java.util.Map;
                                  /**
                                   * 微信用户Controller
                                   *
                                   * @author tigerhhzz
                                   * @date 2023/5/17 15:34
                                   */
                                  @RequestMapping("/user")
                                  @RestController
                                  public class WeixinUserController {
                                      @Autowired
                                      private WxUserInfoService wxUserInfoService;
                                      @Autowired
                                      private WeixinProperties weixinProperties;
                                      @Autowired
                                      private HttpClientUtil httpClientUtil;
                                      /**
                                       * 微信用户登录
                                       * @return
                                       */
                                      @RequestMapping("/wxlogin")
                                      public R wxLogin(@RequestBody WxUserInfo wxUserInfo){
                                          //拼接后端发送请求的URL 例如 https://api.weixin.qq.com/sns/jscode2session?appid=wxa4de78832ea93858&secret=a2efb3b602d96b2dee615b7a4dee451a&js_code=0b1JwPkl2xqHkb4VEjml2vVdua3JwPkq&grant_type=authorization_code
                                          String jscode2sessionUrl=weixinProperties.getJscode2sessionUrl()+"?appid="+weixinProperties.getAppid()+"&secret="+weixinProperties.getSecret()+"&js_code="+wxUserInfo.getCode()+"&grant_type=authorization_code";
                                          System.out.println(jscode2sessionUrl);
                                          //后端向微信后台送发请求 获取openid
                                          String result = httpClientUtil.sendHttpGet(jscode2sessionUrl);
                                          System.out.println(result); //结果:{"session_key":"TPTXzC9MOe1owBJ8zrSWTw==","openid":"o2yqx5PBEW-ezFHA24ASqP0Lk1M0"}
                                          //
                                          JSONObject jsonObject= JSON.parseObject(result);//转换成object
                                          String openid = jsonObject.get("openid").toString();//获取object中openid字段的值;
                                          System.out.println(openid);
                                          // 插入用户到数据库  假如说 用户不存在 我们插入用户  如果用户存在 我们更新用户
                                          WxUserInfo resultWxUserInfo = wxUserInfoService.getOne(new QueryWrapper().eq("openid", openid));
                                          if(resultWxUserInfo==null){
                                              System.out.println("不存在 插入用户");
                                              wxUserInfo.setOpenid(openid);
                                              wxUserInfo.setRegisterDate(new Date());
                                              wxUserInfo.setLastLoginDate(new Date());
                                              wxUserInfoService.save(wxUserInfo);
                                          }else{
                                              System.out.println("存在 更新用户");
                                              // resultWxUserInfo.setNickName(wxUserInfo.getNickName());
                                              // resultWxUserInfo.setAvatarUrl(wxUserInfo.getAvatarUrl());
                                              resultWxUserInfo.setLastLoginDate(new Date());
                                              wxUserInfoService.updateById(resultWxUserInfo);
                                          }
                                          if(resultWxUserInfo!=null && resultWxUserInfo.getStatus().equals("1")){ // 被禁用
                                              return R.error(400,"用户被禁用,具体请联系管理员!");
                                          }else{
                                              // 利用jwt生成token返回到前端
                                              String token = JwtUtils.createJWT(openid, wxUserInfo.getNickName(), JwtConstant.JWT_TTL);
                                              Map resultMap=new HashMap<>();
                                              resultMap.put("token",token);
                                              resultMap.put("openid",openid);
                                              return R.ok(resultMap);
                                          }
                                      }
                                      /**
                                       * 获取当前用户信息
                                       * @return
                                       */
                                      @RequestMapping("/getUserInfo")
                                      public R getUserInfo(@RequestHeader String token){
                                          System.out.println("/getUserInfo----token="+token);
                                          Claims claims = JwtUtils.validateJWT(token).getClaims();
                                          System.out.println("openid="+claims.getId());
                                          WxUserInfo currentUser = wxUserInfoService.getOne(new QueryWrapper().eq("openid", claims.getId()));
                                          Map map=new HashMap<>();
                                          map.put("currentUser",currentUser);
                                          return R.ok(map);
                                      }
                                  }
                                  

                                  前端源码下载地址 https://download.csdn.net/download/weixin_43025151/87803315

                                  后端源码下载地址:https://download.csdn.net/download/weixin_43025151/87803318