步骤
Sa-Token的官网
1.引入依赖和Sa-token依赖
<!--微信支付-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.8</version>
</dependency>
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.37.0</version>
</dependency>
如果是SpringBoot3把sa-token的依赖改为sa-token-spring-boot3-starter
2.配置微信小程序的配置
为了在yml配置里面有提示
ackage com.mbc.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "wechat")
@Data
public class WeChatProperties {
private String appid; //小程序的appid
private String secret; //小程序的秘钥
}
接收前端传给后端的code
package com.mbc.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class UserLoginDTO implements Serializable {
/**
* 微信服务器上的唯一id
*/
private String openId;
/**
* 临时登录凭证
*/
private String code;
}
返回给前端的数据
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
public class UserLoginVO implements Serializable {
/**
* 主键ID
*/
private Long Id;
/**
* 微信服务器上的唯一id
*/
private String openId;
/**
* token
*/
private String token;
}
3.在service层的代码
用了一个Http工具类的工具类
package com.mbc.utils;
import com.alibaba.fastjson.JSONObject;
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.client.utils.URIBuilder;
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;
/**
* Http工具类
*/
public class HttpClientUtil {
static final int TIMEOUT_MSEC = 5 * 1000;
/**
* 发送GET方式请求
* @param url
* @param paramMap
* @return
*/
public static String doGet(String url,Map<String,String> paramMap){
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String result = "";
CloseableHttpResponse response = null;
try{
URIBuilder builder = new URIBuilder(url);
if(paramMap != null){
for (String key : paramMap.keySet()) {
builder.addParameter(key,paramMap.get(key));
}
}
URI uri = builder.build();
//创建GET请求
HttpGet httpGet = new HttpGet(uri);
//发送请求
response = httpClient.execute(httpGet);
//判断响应状态
if(response.getStatusLine().getStatusCode() == 200){
result = EntityUtils.toString(response.getEntity(),"UTF-8");
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
response.close();
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 发送POST方式请求
* @param url
* @param paramMap
* @return
* @throws IOException
*/
public static String doPost(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (paramMap != null) {
List<NameValuePair> paramList = new ArrayList();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
/**
* 发送POST方式请求
* @param url
* @param paramMap
* @return
* @throws IOException
*/
public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
if (paramMap != null) {
//构造json格式数据
JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
jsonObject.put(param.getKey(),param.getValue());
}
StringEntity entity = new StringEntity(jsonObject.toString(),"utf-8");
//设置请求编码
entity.setContentEncoding("utf-8");
//设置数据类型
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
private static RequestConfig builderRequestConfig() {
return RequestConfig.custom()
.setConnectTimeout(TIMEOUT_MSEC)
.setConnectionRequestTimeout(TIMEOUT_MSEC)
.setSocketTimeout(TIMEOUT_MSEC).build();
}
}
@Service
public class UserServiceImpl implements UserService {
//微信服务接口地址
public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
@Autowired
private UserMapper userMapper;
@Autowired
private WeChatProperties weChatProperties;
/**
* WX 登录
*
* @param userLoginDTO 用户登录 DTO
* @return {@link MbcUser}
*/
@Override
@Transactional(rollbackFor = Exception.class)
public UserLoginVO wxLogin(UserLoginDTO userLoginDTO) {
//调用微信接口服务,获得当前微信用户的openid
HashMap<String, String> map = new HashMap<>();
//封装参数
map.put("appid",weChatProperties.getAppid());
map.put("secret",weChatProperties.getSecret());
map.put("js_code",userLoginDTO.getCode());
map.put("grant_type","authorization_code");
//调用微信接口服务,获得当前微信用户的openid
String json = HttpClientUtil.doGet(WX_LOGIN, map);
//解析json,获得openid
JSONObject jsonObject = JSON.parseObject(json);
String openid = jsonObject.getString("openid");
//判断openid是否为空,如果为空表示登录失败,抛出业务异常
if(openid == null){
throw new RuntimeException("微信登录失败");
}
//判断当前用户是否为新用户
MbcUser user = userMapper.getByOpenid(openid);
//如果是新用户,自动完成注册
synchronized (this){
if(user == null){
user = MbcUser.builder()
.openid(openid)
.registeredDate(LocalDateTime.now())
.build();
//执行注册操作
Integer maxUserId = userMapper.getByUserId();
if (maxUserId == null) {
maxUserId = 000001;
user.setUserId(maxUserId);
userMapper.insert(user);
}else {
maxUserId += 1;
user.setUserId(maxUserId);
userMapper.insert(user);
}
}
}
// 使用 Sa-Token 进行登录,并返回Token
StpUtil.login(openid);
String tokenValue = StpUtil.getTokenValue();
UserLoginVO build = UserLoginVO.builder()
.openId(openid)
.token(tokenValue)
.build();
//返回这个用户对象
return build;
}
4.Controller层代码
@RestController
@RequestMapping("/user")
@Api(tags = "基本用户接口")
@Slf4j
@CrossOrigin
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
@ApiOperation("微信登录")
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
//微信登录
UserLoginVO userLoginVO = userService.wxLogin(userLoginDTO);
return Result.success(userLoginVO);
}