Compare commits

...

10 Commits

Author SHA1 Message Date
ed180d6f18 集成MQTT,优化代码 2025-06-27 10:30:27 +08:00
c0c33f6c2e 集成MQTT 2025-06-26 17:14:34 +08:00
953ffdfb28 app显示还回为空的参数 2025-06-25 17:28:57 +08:00
6b9a09c9e8 Merge remote-tracking branch 'origin/dyf-app' into main_app权限适配 2025-06-25 17:07:17 +08:00
64729a223d app端登录权限验证 2025-06-25 16:15:33 +08:00
ec03919c78 Merge remote-tracking branch 'origin/main_app权限适配' into dyf-app
# Conflicts:
#	fys-system/src/main/java/com/fuyuanshen/modules/security/security/app/AppTokenProvider.java
2025-06-25 08:40:02 +08:00
c61f2a7265 app登录响应状态码修改 2025-06-24 18:35:30 +08:00
ae88cc16cc 修改app用户信息 2025-06-24 17:43:45 +08:00
a7bb1d8e84 app端忘记密码redis缓存key字段优化 2025-06-24 13:58:00 +08:00
1f7f4bf537 app端忘记密码功能实现 2025-06-24 13:38:36 +08:00
29 changed files with 765 additions and 55 deletions

View File

@ -0,0 +1,8 @@
package com.fuyuanshen.constants;
public class RedisConstants {
public static final String APP_FORGOT_PASSWORD_SMS_TOKEN = "app_sms_forgotPassword:";
public static final String APP_REGISTER_SMS_TOKEN = "app_sms_register:";
}

View File

@ -0,0 +1,33 @@
package com.fuyuanshen.modules.mqtt.config;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
/**
* @Author: HarryLin
* @Date: 2025/3/20 14:40
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Configuration
public class MqttConfiguration {
@Autowired
private MqttPropertiesConfig mqttPropertiesConfig;
/** 创建连接工厂 **/
@Bean
public MqttPahoClientFactory mqttPahoClientFactory(){
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true); //设置新会话
options.setUserName(mqttPropertiesConfig.getUsername());
options.setPassword(mqttPropertiesConfig.getPassword().toCharArray());
options.setServerURIs(new String[]{mqttPropertiesConfig.getUrl()});
factory.setConnectionOptions(options);
return factory;
}
}

View File

@ -0,0 +1,17 @@
package com.fuyuanshen.modules.mqtt.config;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
/**
* @Author: HarryLin
* @Date: 2025/3/20 17:06
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
public abstract void sendMsgToMqtt(@Header(value = MqttHeaders.TOPIC) String topic, String payload);
public abstract void sendMsgToMqtt(@Header(value = MqttHeaders.TOPIC) String topic, @Header(value = MqttHeaders.QOS) int qos, String payload );
}

View File

@ -0,0 +1,60 @@
package com.fuyuanshen.modules.mqtt.config;
import com.fuyuanshen.modules.mqtt.receiver.ReceiverMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
/**
* @Author: HarryLin
* @Date: 2025/3/20 14:54
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Configuration
public class MqttInboundConfiguration {
@Autowired
private MqttPropertiesConfig mqttPropertiesConfig;
@Autowired
private MqttPahoClientFactory mqttPahoClientFactory;
@Autowired
private ReceiverMessageHandler receiverMessageHandler;
//消息通道
@Bean
public MessageChannel messageInboundChannel(){
return new DirectChannel();
}
/**
* 配置入站适配器
* 作用: 设置订阅主题,以及指定消息的通道 等相关属性
* */
@Bean
public MessageProducer messageProducer(){
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
mqttPropertiesConfig.getUrl(),
mqttPropertiesConfig.getSubClientId(),
mqttPahoClientFactory,
mqttPropertiesConfig.getSubTopic().split(",")
);
mqttPahoMessageDrivenChannelAdapter.setQos(1);
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
mqttPahoMessageDrivenChannelAdapter.setOutputChannel(messageInboundChannel());
return mqttPahoMessageDrivenChannelAdapter;
}
/** 指定处理消息来自哪个通道 */
@Bean
@ServiceActivator(inputChannel = "messageInboundChannel")
public MessageHandler messageHandler(){
return receiverMessageHandler;
}
}

View File

@ -0,0 +1,50 @@
package com.fuyuanshen.modules.mqtt.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
/**
* @Author: HarryLin
* @Date: 2025/3/20 15:46
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Configuration
@Slf4j
public class MqttOutboundConfiguration {
@Autowired
private MqttPropertiesConfig mqttPropertiesConfig;
@Autowired
private MqttPahoClientFactory mqttPahoClientFactory;
// 消息通道
@Bean
public MessageChannel mqttOutboundChannel(){
return new DirectChannel();
}
/** 配置出站消息处理器 */
@Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel") // 指定处理器针对哪个通道的消息进行处理
public MessageHandler mqttOutboundMessageHandler(){
MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(
mqttPropertiesConfig.getUrl(),
mqttPropertiesConfig.getPubClientId(),
mqttPahoClientFactory
);
mqttPahoMessageHandler.setDefaultQos(1);
mqttPahoMessageHandler.setDefaultTopic("worker/location");
mqttPahoMessageHandler.setAsync(true);
return mqttPahoMessageHandler;
}
}

View File

@ -0,0 +1,24 @@
package com.fuyuanshen.modules.mqtt.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author: HarryLin
* @Date: 2025/3/20 14:32
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Data
@ConfigurationProperties(prefix = "mqtt")
@Component
public class MqttPropertiesConfig {
private String username;
private String password;
private String url;
private String subClientId;
private String subTopic;
private String pubClientId;
private String pubTopic;
}

View File

@ -0,0 +1,25 @@
package com.fuyuanshen.modules.mqtt.publish;
import com.fuyuanshen.annotation.rest.AnonymousGetMapping;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/device")
@Slf4j
public class DeviceDataController {
@Autowired
private MqttClientTest mqttClientTest;
// @PostMapping("/{deviceId}/command")
@AnonymousGetMapping(value = "/test/command")
public ResponseEntity<String> sendCommand() {
mqttClientTest.sendMsg();
return ResponseEntity.ok("success");
}
}

View File

@ -0,0 +1,22 @@
package com.fuyuanshen.modules.mqtt.publish;
import com.fuyuanshen.modules.mqtt.config.MqttGateway;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class MqttClientTest {
@Autowired
private MqttGateway mqttGateway;
public void sendMsg() {
mqttGateway.sendMsgToMqtt("worker/location/1", "hello mqtt spring boot");
log.info("message is send");
mqttGateway.sendMsgToMqtt("worker/alert/2", "hello mqtt spring boot2");
log.info("message is send2");
}
}

View File

@ -0,0 +1,25 @@
package com.fuyuanshen.modules.mqtt.publish;
import com.fuyuanshen.modules.mqtt.config.MqttGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;
/**
* @Author: HarryLin
* @Date: 2025/3/20 16:16
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Service
public class MqttMessageSender {
@Autowired
private MqttGateway mqttGateway;
public void sendMsg(@Header(value = MqttHeaders.TOPIC) String topic, String payload) {
mqttGateway.sendMsgToMqtt(topic,payload);
}
public void sendMsg(@Header(value = MqttHeaders.TOPIC) String topic, @Header(value = MqttHeaders.QOS) int qos, String payload) {
mqttGateway.sendMsgToMqtt(topic,qos,payload);
}
}

View File

@ -0,0 +1,31 @@
package com.fuyuanshen.modules.mqtt.receiver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* @Author: HarryLin
* @Date: 2025/3/20 15:24
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Service
@Slf4j
public class ReceiverMessageHandler implements MessageHandler {
@Override
public void handleMessage(Message<?> message) throws MessagingException{
Object payload = message.getPayload();
MessageHeaders headers = message.getHeaders();
String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();
log.info("MQTT payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}"
,payload,receivedTopic,receivedQos,timestamp);
}
}

View File

@ -0,0 +1,25 @@
package com.fuyuanshen.modules.security.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class DeviceDataService {
@ServiceActivator(inputChannel = "mqttInputChannel")
public void handleDeviceData(Message<?> message) {
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
String payload = message.getPayload().toString();
// 解析设备数据
if (topic.startsWith("device/data/")) {
log.info("Received device data device/data/: {} {}", topic, payload);
}
}
}

View File

@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration;
public class LoginProperties {
/**
* 账号单用户 登录
* 账号单用户
*/
private boolean singleLogin = false;

View File

@ -146,7 +146,7 @@ public class AuthController {
@Log("app用户登录")
@ApiOperation("app用户登录")
@AnonymousPostMapping(value = "/app/login")
public ResponseEntity<Object> APPLogin(@Validated @RequestBody AppAuthUserDto authUser, HttpServletRequest request) throws Exception {
public ResponseVO<Object> APPLogin(@Validated @RequestBody AppAuthUserDto authUser, HttpServletRequest request) throws Exception {
// 1. 构建查询参数
APPUserQuery appUserQuery = new APPUserQuery();
@ -196,7 +196,7 @@ public class AuthController {
onlineUserService.saveAppOnlineUser(jwtUser, token, request);
// 11. 返回结果
return ResponseEntity.ok(authInfo);
return ResponseVO.success(authInfo);
}

View File

@ -16,14 +16,19 @@
package com.fuyuanshen.modules.system.domain.app;
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 com.fuyuanshen.modules.system.domain.Role;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.fuyuanshen.base.BaseEntity;
import com.fuyuanshen.utils.enums.DataScopeEnum;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
* 角色
@ -32,12 +37,49 @@ import javax.validation.constraints.NotNull;
*/
@Getter
@Setter
@TableName("app_sys_role")
public class APPRole extends Role {
@TableName("sys_role")
public class APPRole extends BaseEntity implements Serializable {
@NotNull(groups = {Update.class})
@TableId(value="app_role_id", type = IdType.AUTO)
@TableId(value="role_id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@TableField(exist = false)
@ApiModelProperty(value = "用户", hidden = true)
private Set<APPUser> users;
@TableField(exist = false)
@ApiModelProperty(value = "菜单", hidden = true)
private Set<APPMenu> menus;
@NotBlank
@ApiModelProperty(value = "名称", hidden = true)
private String name;
@ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义")
private String dataScope = DataScopeEnum.THIS_LEVEL.getValue();
@ApiModelProperty(value = "级别,数值越小,级别越大")
private Integer level = 3;
@ApiModelProperty(value = "描述")
private String description;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
APPRole role = (APPRole) o;
return Objects.equals(id, role.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@ -133,4 +133,8 @@ public class APPUser extends BaseEntity implements Serializable {
@ApiModelProperty(hidden = true)
private Integer userType;
/**
* 地区
*/
private String region;
}

View File

@ -0,0 +1,27 @@
package com.fuyuanshen.modules.system.domain.dto.app;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author: 默苍璃
* @date: 2025-06-1818:36
*/
@Data
public class APPForgotPasswordDTO {
@NotBlank(message = "手机号不能为空")
@ApiModelProperty(value = "手机号APP登录")
private String phoneNumber;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
@NotBlank(message = "验证码不能为空")
private String verificationCode;
}

View File

@ -0,0 +1,32 @@
package com.fuyuanshen.modules.system.domain.dto.app;
import com.fuyuanshen.modules.system.domain.app.APPUser;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotBlank;
/**
* @author: 默苍璃
* @date: 2025-06-1818:36
*/
@Data
public class APPUpdateUserDTO {
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@ApiModelProperty(value = "用户昵称")
private String nickName;
@ApiModelProperty(value = "地区")
private String region;
@ApiModelProperty(value = "用户性别")
private String gender;
@ApiModelProperty(value = "头像图片")
private MultipartFile file;
}

View File

@ -0,0 +1,40 @@
package com.fuyuanshen.modules.system.domain.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author: 默苍璃
* @date: 2025-06-1211:34
*/
@Data
@JsonInclude(JsonInclude.Include.ALWAYS)
public class APPUserVo {
@ApiModelProperty(value = "ID")
@JsonProperty("id")
private Long id;
@ApiModelProperty(value = "用户昵称")
@JsonProperty("nickName")
private String nickName;
@ApiModelProperty(value = "用户性别")
@JsonProperty("gender")
private String gender;
@ApiModelProperty(value = "电话号码")
@JsonProperty("phone")
private Long phone;
@ApiModelProperty(value = "头像存储的路径")
@JsonProperty("avatarPath")
private String avatarPath;
@ApiModelProperty(value = "地区")
@JsonProperty("region")
private String region;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.modules.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fuyuanshen.modules.system.domain.Role;
import com.fuyuanshen.modules.system.domain.app.APPRole;
import com.fuyuanshen.modules.system.domain.dto.RoleQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Set;
/**
* @author Zheng Jie
* @date 2023-06-20
*/
@Mapper
public interface APPRoleMapper extends BaseMapper<APPRole> {
List<APPRole> findByUserId(@Param("userId") Long userId);
}

View File

@ -15,54 +15,30 @@
*/
package com.fuyuanshen.modules.system.rest.app;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.annotation.Log;
import com.fuyuanshen.annotation.rest.AnonymousPostMapping;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.security.service.UserCacheManager;
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.Dept;
import com.fuyuanshen.modules.system.domain.Role;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.app.APPUser;
import com.fuyuanshen.modules.system.domain.dto.UserPassVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.UserQueryCriteria;
import com.fuyuanshen.modules.system.domain.dto.app.APPForgotPasswordDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUpdateUserDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUserDTO;
import com.fuyuanshen.modules.system.domain.query.APPUserQuery;
import com.fuyuanshen.modules.system.domain.vo.ConsumerVo;
import com.fuyuanshen.modules.system.domain.vo.APPUserVo;
import com.fuyuanshen.modules.system.enums.UserType;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.service.*;
import com.fuyuanshen.modules.system.service.app.APPUserService;
import com.fuyuanshen.modules.utils.ResponseVO;
import com.fuyuanshen.utils.PageResult;
import com.fuyuanshen.utils.SecurityUtils;
import com.fuyuanshen.utils.StringUtils;
import com.fuyuanshen.utils.enums.CodeEnum;
import io.netty.util.internal.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.apache.ibatis.annotations.Param;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Zheng Jie
@ -91,10 +67,17 @@ public class APPUserController {
@ApiOperation("用户中心")
@GetMapping(value = "/get")
@PreAuthorize("@el.check('appUser:get')")
public ResponseVO<APPUser> getAPPUser(UserQueryCriteria criteria) {
public ResponseVO<APPUserVo> getAPPUser() {
String userName = SecurityUtils.getCurrentUsername();
return null;
// return ResponseVO.success(appUserService.getAPPUser(criteria));
APPUser appUser = appUserService.getLoginData(userName);
APPUserVo appUserVo = new APPUserVo();
appUserVo.setId(appUser.getId());
appUserVo.setNickName(appUser.getNickName());
appUserVo.setGender(appUser.getGender());
appUserVo.setPhone(appUser.getPhone());
return ResponseVO.success(appUserVo);
}
@Log("app用户注册")
@ -103,21 +86,52 @@ public class APPUserController {
public ResponseVO<String> APPRegister(@Validated @RequestBody APPUserDTO user) throws Exception {
//暫定0000
if (user.getVerificationCode() == null || !"0000".equals(user.getVerificationCode())) {
if (!"0000".equals(user.getVerificationCode())) {
throw new BadRequestException("验证码错误");
}
appUserService.addUser(user);
return ResponseVO.success("success");
}
@Log("发送用户注册验证码")
@ApiOperation("发送用户注册验证码")
@AnonymousPostMapping(value = "/sendRegisterSms")
public ResponseVO<String> sendRegisterSms(@Param("phoneNumber") String phoneNumber) throws Exception {
// appUserService.sendSms(phoneNumber);
return ResponseVO.success("success");
}
@Log("修改APP用户")
@ApiOperation("修改APP用户")
@PutMapping
@PreAuthorize("@el.check('appUser:edit')")
public ResponseVO<String> updateUser(@Validated(APPUser.Update.class) @RequestBody APPUser appUser) throws Exception {
appUserService.updateById(appUser);
public ResponseVO<String> updateUser(@Validated @ModelAttribute APPUpdateUserDTO appUser) throws Exception {
Long userId = SecurityUtils.getCurrentUserId();
if(!userId.equals(appUser.getId())){
throw new BadRequestException("不能修改他人资料");
}
appUserService.updateUser(appUser);
return ResponseVO.success("success");
}
@Log("忘记密码")
@ApiOperation("忘记密码")
@AnonymousPostMapping(value = "/forgotPassword")
public ResponseVO<String> forgotPassword(@RequestBody APPForgotPasswordDTO appForgotPasswordDTO) throws Exception {
if (!"0000".equals(appForgotPasswordDTO.getVerificationCode())) {
throw new BadRequestException("验证码错误");
}
appUserService.forgotPassword(appForgotPasswordDTO);
return ResponseVO.success("success");
}
@Log("发送忘记密码验证码")
@ApiOperation("发送忘记密码验证码")
@AnonymousPostMapping(value = "/sendForgotPasswordSms")
public ResponseVO<String> sendForgotPasswordSms(@Param("phoneNumber") String phoneNumber) throws Exception {
// appUserService.sendSms(phoneNumber);
return ResponseVO.success("success");
}
}

View File

@ -21,6 +21,8 @@ import com.fuyuanshen.modules.security.service.dto.app.AppRoleDto;
import com.fuyuanshen.modules.system.domain.Role;
import com.fuyuanshen.modules.system.domain.app.APPUser;
import com.fuyuanshen.modules.system.domain.dto.UserQueryCriteria;
import com.fuyuanshen.modules.system.domain.dto.app.APPForgotPasswordDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUpdateUserDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUserDTO;
import com.fuyuanshen.modules.utils.ResponseVO;
import com.fuyuanshen.utils.PageResult;
@ -54,4 +56,10 @@ public interface APPUserService extends IService<APPUser> {
ResponseVO<Object> addUser(APPUserDTO user);
Integer selectRoleByUserLevel(Set<Role> roles);
void forgotPassword(APPForgotPasswordDTO appForgotPasswordDTO);
void sendSms(String phoneNumber);
void updateUser(APPUpdateUserDTO appUser);
}

View File

@ -19,7 +19,10 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.modules.system.domain.app.APPMenu;
import com.fuyuanshen.modules.system.domain.app.APPRole;
import com.fuyuanshen.modules.system.domain.app.APPUser;
import com.fuyuanshen.modules.system.mapper.*;
import lombok.RequiredArgsConstructor;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.security.service.UserCacheManager;
@ -28,10 +31,6 @@ import com.fuyuanshen.modules.system.domain.Menu;
import com.fuyuanshen.modules.system.domain.Role;
import com.fuyuanshen.exception.EntityExistException;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.mapper.RoleDeptMapper;
import com.fuyuanshen.modules.system.mapper.RoleMapper;
import com.fuyuanshen.modules.system.mapper.RoleMenuMapper;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.service.RoleService;
import com.fuyuanshen.modules.system.domain.dto.RoleQueryCriteria;
import com.fuyuanshen.utils.*;
@ -53,6 +52,7 @@ import java.util.stream.Collectors;
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
private final RoleMapper roleMapper;
private final APPRoleMapper appRoleMapper;
private final RoleDeptMapper roleDeptMapper;
private final RoleMenuMapper roleMenuMapper;
private final RedisUtils redisUtils;
@ -206,8 +206,8 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
permissions.add("admin");
return permissions.stream().map(AuthorityDto::new).collect(Collectors.toList());
}
List<Role> roles = roleMapper.findByUserId(user.getId());
permissions = roles.stream().flatMap(role -> role.getMenus().stream()).map(Menu::getPermission).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
List<APPRole> roles = appRoleMapper.findByUserId(user.getId());
permissions = roles.stream().flatMap(role -> role.getMenus().stream()).map(APPMenu::getPermission).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
authorityDtos = permissions.stream().map(AuthorityDto::new).collect(Collectors.toList());
redisUtils.set(key, authorityDtos, 1, TimeUnit.HOURS);
}

View File

@ -15,24 +15,35 @@
*/
package com.fuyuanshen.modules.system.service.impl.app;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.constants.DeviceConstants;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.system.domain.Role;
import com.fuyuanshen.modules.system.domain.app.APPUser;
import com.fuyuanshen.modules.system.domain.dto.UserQueryCriteria;
import com.fuyuanshen.modules.system.domain.dto.app.APPForgotPasswordDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUpdateUserDTO;
import com.fuyuanshen.modules.system.domain.dto.app.APPUserDTO;
import com.fuyuanshen.modules.system.mapper.app.APPUserMapper;
import com.fuyuanshen.modules.system.service.app.APPUserService;
import com.fuyuanshen.modules.utils.ResponseVO;
import com.fuyuanshen.utils.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import static com.fuyuanshen.constants.RedisConstants.*;
/**
* @author Zheng Jie
* @date 2018-11-23
@ -45,6 +56,19 @@ public class APPUserServiceImpl extends ServiceImpl<APPUserMapper, APPUser> impl
private final PasswordEncoder passwordEncoder;
@Autowired
private final RedisUtils redisUtils;
@Value("${file.app_avatar.pic}")
private String filePath;
@Value("${file.app_avatar.ip}")
private String ip;
/**
* 文件访问路径前缀
*/
public static final String FILE_ACCESS_PREFIX = "images";
public static final String FILE_AVATAR_PREFIX = "avatar";
/**
* 查询APP/小程序用户
*
@ -73,6 +97,14 @@ public class APPUserServiceImpl extends ServiceImpl<APPUserMapper, APPUser> impl
if (appUserMapper.getByUsername(username) != null) {
throw new BadRequestException("该手机号已被注册");
}
/* Object verificationCode = redisUtils.get(APP_REGISTER_SMS_TOKEN + username);
if (verificationCode == null) {
throw new BadRequestException("验证码已过期");
}
if(!user.getVerificationCode().equals(verificationCode.toString())){
throw new BadRequestException("验证码错误");
}*/
APPUser appUser = new APPUser();
appUser.setUsername(user.getPhoneNumber());
@ -96,4 +128,67 @@ public class APPUserServiceImpl extends ServiceImpl<APPUserMapper, APPUser> impl
return 0;
}
@Override
public void forgotPassword(APPForgotPasswordDTO appForgotPasswordDTO) {
String phoneNumber = appForgotPasswordDTO.getPhoneNumber();
APPUser appUser = appUserMapper.appFindByUsername(phoneNumber);
if (appUser == null) {
throw new BadRequestException("手机号不存在");
}
/*Object verificationCode = redisUtils.get(APP_FORGOT_PASSWORD_SMS_TOKEN + phoneNumber);
if (verificationCode == null) {
throw new BadRequestException("验证码已过期");
}
if(!appForgotPasswordDTO.getVerificationCode().equals(verificationCode.toString())){
throw new BadRequestException("验证码错误");
}*/
appUser.setPassword(appForgotPasswordDTO.getPassword());
appUserMapper.updateById(appUser);
}
@Override
public void sendSms(String phoneNumber) {
if (appUserMapper.appFindByUsername(phoneNumber) == null) {
throw new BadRequestException("手机号不存在");
}
// todo 发送验证码
redisUtils.set(APP_FORGOT_PASSWORD_SMS_TOKEN + phoneNumber, RandomUtil.randomNumbers(4), 5 * 60);
}
@Override
public void updateUser(APPUpdateUserDTO appUser) {
APPUser updUser= new APPUser();
updUser.setId(appUser.getId());
updUser.setNickName(appUser.getNickName());
try {
updUser.setAvatarPath(saveUserAvatarImage(appUser.getFile()));
}catch (IOException e){
throw new BadRequestException("上传头像失败");
}
updUser.setRegion(appUser.getRegion());
updUser.setGender(appUser.getGender());
appUserMapper.updateById(updUser);
}
private String saveUserAvatarImage(MultipartFile file) throws IOException {
if (file == null || file.isEmpty()) {
return null;
}
String originalFileName = file.getOriginalFilename();
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
String newFileName = "PS_" + RandomUtil.randomNumbers(8) + "." + fileExtension;
File newFile = new File(filePath + FILE_AVATAR_PREFIX + File.separator + newFileName);
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
file.transferTo(newFile);
return ip + DeviceConstants.FILE_ACCESS_PREFIX + "/" + FILE_AVATAR_PREFIX + "/" + newFileName;
}
}

View File

@ -4,9 +4,9 @@ spring:
druid:
db-type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://192.168.2.23:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
url: jdbc:p6spy:mysql://120.79.224.186:3366/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
password: root
password: 1fys@QWER..
# 初始连接数,建议设置为与最小空闲连接数相同
initial-size: 20
# 最小空闲连接数,保持足够的空闲连接以应对请求
@ -53,10 +53,10 @@ spring:
redis:
#数据库索引
database: ${REDIS_DB:2}
host: ${REDIS_HOST:123.207.99.140}
port: ${REDIS_PORT:6379}
password: ${REDIS_PWD:ccxx11234}
database: ${REDIS_DB:0}
host: ${REDIS_HOST:120.79.224.186}
port: ${REDIS_PORT:26379}
password: ${REDIS_PWD:1fys@QWER..}
#连接超时时间
timeout: 5000
# 连接池配置
@ -141,7 +141,20 @@ file:
device:
pic: C:\eladmin\file\ #设备图片存储路径
ip: http://fuyuanshen.com:81/ #服务器地址
app_avatar:
pic: C:\eladmin\file\ #设备图片存储路径
#ip: http://fuyuanshen.com:81/ #服务器地址
ip: https://fuyuanshen.com/ #服务器地址
logging:
level:
com.fuyuanshen: debug
# MQTT配置
mqtt:
username: admin
password: fys123456
url: tcp://127.0.0.1:1883
subClientId: wuLang_subClient_01
subTopic: worker/alert/#,worker/location/#
pubTopic: worker/location
pubClientId: wuLang_pubClient_01

View File

@ -151,3 +151,7 @@ file:
pic: /home/eladmin/file/ #设备图片存储路径
#ip: http://fuyuanshen.com:81/ #服务器地址
ip: https://fuyuanshen.com/ #服务器地址
app_avatar:
pic: /home/eladmin/app_avatar/ #设备图片存储路径
#ip: http://fuyuanshen.com:81/ #服务器地址
ip: https://fuyuanshen.com/ #服务器地址

View File

@ -43,6 +43,8 @@ spring:
multipart:
max-file-size: 5MB # 设置单个上传文件的最大大小为10MB
max-request-size: 5MB
jackson:
default-property-inclusion: non_null
# pid:
# file: /自行指定位置/eladmin.pid

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.fuyuanshen.modules.system.mapper.APPRoleMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.modules.system.domain.app.APPRole">
<id column="role_role_id" property="id"/>
<result column="role_name" property="name"/>
<result column="role_data_scope" property="dataScope"/>
<result column="role_level" property="level"/>
<result column="role_description" property="description"/>
<result column="role_create_by" property="createBy"/>
<result column="role_update_by" property="updateBy"/>
<result column="role_create_time" property="createTime"/>
<result column="role_update_time" property="updateTime"/>
<collection property="menus" ofType="com.fuyuanshen.modules.system.domain.app.APPMenu">
<id column="menu_id" property="id"/>
<result column="menu_title" property="title"/>
<result column="menu_permission" property="permission"/>
</collection>
</resultMap>
<sql id="Base_Column_List">
role.role_id as role_role_id, role.name as role_name, role.data_scope as role_data_scope,
role.level as role_level, role.description as role_description, role.create_by as role_create_by,
role.update_by as role_update_by, role.create_time as role_create_time, role.update_time as role_update_time
</sql>
<sql id="Menu_Column_List">
menu.menu_id as menu_id, menu.title as menu_title, menu.permission as menu_permission
</sql>
<sql id="Dept_Column_List">
dept.dept_id as dept_id, dept.name as dept_name
</sql>
<sql id="Where_sql">
<where>
<if test="criteria.blurry != null and criteria.blurry != ''">
and (
role.name like concat('%', #{criteria.blurry}, '%')
or role.description like concat('%', #{criteria.blurry}, '%')
)
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and role.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
</where>
</sql>
<select id="findByUserId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>,
<include refid="Menu_Column_List"/>
from app_role role
left join app_roles_menus srm on role.role_id = srm.role_id
left join app_menu menu on menu.menu_id = srm.menu_id
left join app_users_roles ur on role.role_id = ur.role_id
WHERE role.role_id = ur.role_id AND ur.user_id = #{userId}
</select>
</mapper>

View File

@ -223,6 +223,14 @@
<artifactId>commons-text</artifactId>
<version>1.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
</dependencies>
<build>