1. 快速登录

2. 文章列表
3. 设备绑定用户
This commit is contained in:
邱贞招 2024-02-23 17:08:05 +08:00
parent b1c21d7f90
commit 65591bb3f6
16 changed files with 402 additions and 64 deletions

View File

@ -4,8 +4,11 @@ import java.util.List;
import java.util.Set;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.device.domain.AsDevice;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.system.service.ISysUserService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -90,7 +93,10 @@ public class SysLoginController
public AjaxResult getAppInfo()
{
AsUser user = SecurityUtils.getLoginUser().getAsUser();
user.setDeviceId(asUserService.selectDeviceInfoByUser(user.getUserId(),null).get(0).getDeviceId());
List<AsDevice> asDevices = asUserService.selectDeviceInfoByUser(user.getUserId(), null);
if(ObjectUtils.isNotEmpty(asDevices) && asDevices.size()!=0){
user.setDeviceId(asDevices.get(0).getDeviceId());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
return ajax;
@ -121,4 +127,16 @@ public class SysLoginController
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 微信登录
*/
@PostMapping("/wxlogin")
public AjaxResult wxlogin(String mobileCode) {
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.wxloing(mobileCode);
ajax.put(Constants.TOKEN, token);
return ajax;
}
}

View File

@ -25,6 +25,12 @@
<version>3.1.284</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.6.0</version>
</dependency>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>

View File

@ -175,6 +175,11 @@ public class Constants
*/
public static final String CUSTOM_LOGIN_SMS = "sms_login";
/**
* 微信登录
*/
public static final String CUSTOM_LOGIN_WX = "wx_login";
/**
* 短信验证码有效期 10分钟
* */

View File

@ -13,6 +13,9 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.alibaba.fastjson2.JSON;
import com.squareup.okhttp.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.Constants;
@ -184,6 +187,26 @@ public class HttpUtils
}
return result.toString();
}
//
// public static String sendPostWithToken2(String url, String param, String token){
// OkHttpClient client = new OkHttpClient();
//
// MediaType mediaType = MediaType.parse("text/html");
// RequestBody body = RequestBody.create(mediaType, "open");
// Request request = new Request.Builder()
// .url("https://iot-api.heclouds.com/datapoint/synccmds?device_name=4827E2945C58&product_id=50dd83E8zQ&timeout=10")
// .post(body)
// .addHeader("Authorization", "version=2020-05-29&res=userid/143831&et=1710933295&method=sha256&sign=4NfxXMuNOa110dVTYjlJfOmlMiw7tiScwCxo5HQ/7g8=")
// .addHeader("content-type", "text/html")
// .build();
// Response response = null;
// try {
// response = client.newCall(request).execute();
// } catch (IOException e) {
// e.printStackTrace();
// }
// return JSON.toJSONString(response);
// }
/**
* 向指定 URL 发送POST方法的请求
*
@ -206,7 +229,7 @@ public class HttpUtils
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setRequestProperty("content-type", "text/html");
conn.setRequestProperty("Authorization", token);
conn.setDoOutput(true);
conn.setDoInput(true);

View File

@ -0,0 +1,44 @@
package com.ruoyi.common.utils.wx;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.wx.vo.AccessToken;
import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;
public class AccessTokenUtil {
/** 缓存token */
private static String cachedToken;
/** token过期时间 */
private static long tokenExpirationTime;
@SneakyThrows
public static String getToken() {
if (isTokenExpired()) {
String APPID = SpringUtils.getRequiredProperty("wx.appid");
String APPSECRET = SpringUtils.getRequiredProperty("wx.appSecret");
WxMaService wxMaService = new WxMaServiceImpl();
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(APPID);
config.setSecret(APPSECRET);
wxMaService.setWxMaConfig(config);
String accessToken = wxMaService.getAccessToken();
cachedToken = accessToken;
// 更新 token 过期时间
tokenExpirationTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(7200L);
return cachedToken;
}
return cachedToken;
}
/**判断token是否过期*/
private static boolean isTokenExpired() {
return cachedToken == null || System.currentTimeMillis() > tokenExpirationTime;
}
}

View File

@ -0,0 +1,83 @@
package com.ruoyi.common.utils.wx.vo;
public class AccessToken {
private String expires_in; //成功有效时间
private String access_token; // 普通Token
private String refresh_token; // 普通Token
private String openid;
private String errcode; //失败ID
private String errmsg; //失败消息
private long expiresIn; //过期时间 默认2小时
public long getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(long expiresIn) {
this.expiresIn = expiresIn;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getRefresh_token() {
return refresh_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
/**
*
* @param expires_in 从微信服务器获取到的过期时间
* @param access_token 从微信服务器获取到的过期时间access-token
*/
public AccessToken(String expires_in, String access_token) {
this.access_token = access_token;
//当前系统时间+上过期时间
expiresIn = System.currentTimeMillis() + Integer.parseInt(expires_in) * 1000;
}
//判断token是否过期
public boolean isExpired() {
return System.currentTimeMillis() > expiresIn;
}
}

View File

@ -113,7 +113,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage","/common/receive","/appCaptcha","/appCodeLogin","/app/**","/common/upload").permitAll()
.antMatchers("/login","/wxlogin", "/register", "/captchaImage","/common/receive","/appCaptcha","/appCodeLogin","/app/**","/common/upload").permitAll()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

@ -26,7 +26,7 @@ public class CustomLoginAuthenticationProvider extends DaoAuthenticationProvider
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
String password = authentication.getCredentials().toString();
if(Constants.CUSTOM_LOGIN_SMS.equals(password)){
if(Constants.CUSTOM_LOGIN_SMS.equals(password) || Constants.CUSTOM_LOGIN_WX.equals(password)){
//短信登录不验证密码
}else{
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

View File

@ -2,9 +2,20 @@ package com.ruoyi.framework.web.service;
import javax.annotation.Resource;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.wx.AccessTokenUtil;
import com.ruoyi.common.utils.wx.vo.AccessToken;
import com.ruoyi.device.service.IAsUserService;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -58,6 +69,13 @@ public class SysLoginService
@Autowired
private ISysConfigService configService;
@Value("${wx.appid}")
private String APPID;
@Value("${wx.appSecret}")
private String APPSECRET;
/**
* 登录验证
*
@ -237,4 +255,60 @@ public class SysLoginService
// 生成token
return tokenService.createToken(loginUser);
}
/**
* 微信登录
*/
public String wxloing(String mobileCode) {
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
String phoneNumber = null;
AsUser user = null;
/** 根据手机号获取到用户名*/
String token = AccessTokenUtil.getToken();
url = url+token;
JSONObject jsonObject = new JSONObject();
jsonObject.put("code",mobileCode);
String post = HttpUtils.sendPost(url,jsonObject.toString());
JSONObject jsonObject1 = JSONObject.parseObject(post);
String phoneInfo = jsonObject1.getString("phone_info");
WxMaPhoneNumberInfo wxMaPhoneNumberInfo = JSONObject.parseObject(phoneInfo, WxMaPhoneNumberInfo.class);
phoneNumber = wxMaPhoneNumberInfo.getPhoneNumber();
user = asUserService.selectUserByPhone(phoneNumber);
if(ObjectUtils.isEmpty(user)){
AsUser asUser = new AsUser();
asUser.setUserName(phoneNumber);
asUser.setPhonenumber(phoneNumber);
asUser.setLoginIp(IpUtils.getIpAddr());
asUser.setLoginDate(DateUtils.getNowDate());
asUser.setCreateTime(DateUtils.getNowDate());
int i = asUserService.insertUser(asUser);
user = asUser;
}
Authentication authentication = null; // 用户验证
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), Constants.CUSTOM_LOGIN_WX);
// 用户名和密码等信息保存在一个上下文中只要是同一线程等会就能拿到用户名和密码也就是能在loadUserByUsername(String username)方法中进行密码验证等
AuthenticationContextHolder.setContext(authenticationToken);
// 把用户类型放在上下文中的details属性中在UserDetailsServiceImpl.loadUserByUsername中获取
authenticationToken.setDetails(Constants.USER_TYPE_APP);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
catch (Exception e) {
if (e instanceof BadCredentialsException) {
throw new UserPasswordNotMatchException(); //抛出账号或者密码错误的异常
} else {
throw new ServiceException(e.getMessage()); //抛出其他异常
}
} finally {
AuthenticationContextHolder.clearContext();
}
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordAppLoginInfo(loginUser.getUserId());
return tokenService.createToken(loginUser);
}
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1701826791485" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5646" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M356.573 768.21h-255.83v-36.537h255.83v-73.55h-255.83v-36.535h255.83v-72.435h-255.83v-37.93h255.83v-71.279h-255.83v-36.536h255.83V183.317H27.631V1024h621.388l0.08-146.741-292.526-0.319V768.21zM795.203 0v219.295h219.334L795.203 0zM760.02 1.355H393.15v839.05h621.388V256.786l-254.516-0.16V1.356z m181.405 693.384H466.26v-35.181h475.166v35.181z m0-109.17H466.26v-37.053h475.166v37.054z m0-146.222v36.535H466.26v-36.535h475.166z" fill="#bfbfbf" p-id="5647"></path></svg>

After

Width:  |  Height:  |  Size: 799 B

View File

@ -3,6 +3,7 @@ package com.ruoyi.device.app;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
@ -19,6 +20,7 @@ import com.ruoyi.device.service.IAsDeviceService;
import com.ruoyi.device.service.IAsDeviceVersionService;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.device.service.IAsWateringRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@ -118,6 +120,15 @@ public class AppController extends BaseController
return success(asDeviceService.selectAsDeviceByDeviceId(deviceId));
}
/**
* 绑定设备
*/
@GetMapping(value = "/bandDevice")
public AjaxResult getInfo(@RequestBody AsDevice asDevice)
{
return success(asDeviceService.bandDevice(asDevice));
}
/**
* 删除设备列表
*/

View File

@ -15,13 +15,21 @@ import com.ruoyi.system.domain.SysStudent;
public interface AsDeviceMapper extends BaseMapper<AsDevice>
{
/**
* 查询设备列表
* 查询设备详情
*
* @param deviceId 设备列表主键
* @return 设备列表
*/
public AsDevice selectAsDeviceByDeviceId(Long deviceId);
/**
* 查询设备列表
*
* @param mac 设备列表主键
* @return 设备列表
*/
public AsDevice selectAsDeviceByMac(String mac);
/**
* 查询设备列表列表
*

View File

@ -68,4 +68,12 @@ public interface IAsDeviceService
* @return 结果
*/
public AjaxResult watering(AsDevice device,Integer wateringSwitch);
/**
* 绑定设备
*
* @param asDevice 设备
* @return 结果
*/
int bandDevice(AsDevice asDevice);
}

View File

@ -16,6 +16,7 @@ import com.ruoyi.device.mapper.*;
import com.ruoyi.device.service.IAsDeviceService;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@ -89,6 +90,9 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
public AsDevice selectAsDeviceByDeviceId(Long deviceId)
{
AsDevice device = asDeviceMapper.selectAsDeviceByDeviceId(deviceId);
if(ObjectUtils.isEmpty(device)){
throw new ServiceException("没有找到该设备");
}
device.setPicture(modelMapper.selectAsModelByModelId(device.getModelId()).getPicture());
return device;
}
@ -111,9 +115,11 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
asDevice1.setPicture(picture);
// 查询onenet设备在线状态
String sendUrl = iotUrl+ IotConstants.ADDS_COMMAND;
String deviceName = asDevice1.getMac();//mac地址就是产品名称
String param = "device_name=" + deviceName + "&product_id=" + productId +"&timeout=" + timeout;
sendUrl = sendUrl + "?"+param;
String token = Token.getToken();
String result = HttpUtils.sendPostWithToken(sendUrl, "111", token);
JSONObject paramsObj = JSON.parseObject(result);
String code = paramsObj.getString("code");
if (!HttpStatus.IOT_SUCCESS.equals(code)) {
@ -328,4 +334,22 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i
int insert = wateringRecordMapper.insertAsWateringRecord(record);
return AjaxResult.success(insert);
}
/**
* 绑定设备
*
* @param asDevice 设备对象
* @return 结果
*/
@Override
public int bandDevice(AsDevice asDevice) {
/** 根据mac号获取到设备详情*/
String mac = asDevice.getMac();
AsDevice device = asDeviceMapper.selectAsDeviceByMac(mac);
if(ObjectUtils.isNotEmpty(device.getUserId())){
throw new ServiceException("该设备已经绑定用户,请先解绑!");
}
device.setUserId(asDevice.getUserId());
return asDeviceMapper.updateAsDevice(device);
}
}

View File

@ -1,23 +1,31 @@
package com.ruoyi.device.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.onenet.Token;
import com.ruoyi.device.domain.AsDevice;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.device.mapper.AsDeviceMapper;
import com.ruoyi.device.mapper.AsUserMapper;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -48,6 +56,15 @@ public class AsUserServiceImpl implements IAsUserService
@Autowired
protected Validator validator;
@Value(value = "${watering.iotUrl}")
private String iotUrl;
@Value(value = "${watering.productId}")
private String productId;
@Value(value = "${watering.timeout}")
private String timeout;
/**
* 根据条件分页查询用户列表
*
@ -392,16 +409,27 @@ public class AsUserServiceImpl implements IAsUserService
* @param userId 用户id
* @return 用户设备信息
*/
@SneakyThrows
@Override
public List<AsDevice> selectDeviceInfoByUser(Long userId,Long deviceId) {
AsDevice asDevice = AsDevice.builder().userId(userId).deviceId(deviceId).build();
List<AsDevice> asDevices = asDeviceMapper.selectAsDeviceList(asDevice);
// if(ObjectUtils.isNotEmpty(asDevices) && asDevices.size() !=0 ){
// AsDevice device = asDevices.get(0);
// //请求
//
// return device;
// }
// 查询onenet设备在线状态
String sendUrl = iotUrl+ IotConstants.ADDS_COMMAND;
String token = Token.getToken();
for(AsDevice asDevice1 : asDevices){
String deviceName = asDevice1.getMac();//mac地址就是产品名称
String param = "device_name=" + deviceName + "&product_id=" + productId +"&timeout=" + timeout;
sendUrl = sendUrl + "?"+param;
String result = HttpUtils.sendPostWithToken(sendUrl, "111", token);
JSONObject paramsObj = JSON.parseObject(result);
String code = paramsObj.getString("code");
if (!HttpStatus.IOT_SUCCESS.equals(code)) {
asDevice1.setOnlineStatus("不在线");
}else{
asDevice1.setOnlineStatus("在线");
}
}
return asDevices;
}
}

View File

@ -60,6 +60,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where device_id = #{deviceId}
</select>
<select id="selectAsDeviceByMac" parameterType="String" resultMap="AsDeviceResult">
<include refid="selectAsDeviceVo"/>
where mac = #{mac}
</select>
<insert id="insertAsDevice" parameterType="AsDevice" useGeneratedKeys="true" keyProperty="deviceId">
insert into as_device
<trim prefix="(" suffix=")" suffixOverrides=",">