Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
13
pom.xml
13
pom.xml
@@ -46,6 +46,9 @@
|
||||
<sendgrid.version>4.10.3</sendgrid.version>
|
||||
<gson.version>2.12.1</gson.version>
|
||||
|
||||
<httpmime.version>4.5.14</httpmime.version>
|
||||
<Java-WebSocket.version>1.5.4</Java-WebSocket.version>
|
||||
<twilio.version>10.1.1</twilio.version>
|
||||
|
||||
</properties>
|
||||
|
||||
@@ -301,13 +304,19 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>4.5.14</version>
|
||||
<version>${httpmime.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.5.4</version> <!-- 最新版本可到 Maven 仓库查询 -->
|
||||
<version>${Java-WebSocket.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twilio.sdk</groupId>
|
||||
<artifactId>twilio</artifactId>
|
||||
<version>${twilio.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -45,19 +45,6 @@ public class ChatWebSocketHandler {
|
||||
// @Value("${whisper.language}")
|
||||
private String language = "en";
|
||||
|
||||
/**
|
||||
* 16kHz
|
||||
*/
|
||||
private static final int SAMPLE_RATE = 16000;
|
||||
/**
|
||||
* 4 KB 每次读取
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
/**
|
||||
* 每样本 16 位
|
||||
*/
|
||||
private static final int BITS_PER_SAMPLE = 16;
|
||||
|
||||
/**
|
||||
* 缓存客户端流式解析的语音文本数据
|
||||
*/
|
||||
@@ -68,12 +55,6 @@ public class ChatWebSocketHandler {
|
||||
*/
|
||||
private final Map<String, WebSocket> cacheWebSocket = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 为每个会话维护分片缓存(线程安全,支持多用户)
|
||||
*/
|
||||
private final ConcurrentHashMap<String, List<byte[]>> fragmentCache = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
// 语音文件保存目录
|
||||
private static final String VOICE_STORAGE_DIR = "/voice_files/";
|
||||
|
||||
@@ -98,6 +79,7 @@ public class ChatWebSocketHandler {
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("clientId") String clientId) {
|
||||
log.info("WebSocket 链接已建立:{}", clientId);
|
||||
log.info("WebSocket session 链接已建立:{}", session.getId());
|
||||
cacheClientTts.put(clientId,new String());
|
||||
//初始化STT流式语音转换文本的socket链接
|
||||
createWhisperRealtimeSocket(clientId);
|
||||
@@ -116,26 +98,14 @@ public class ChatWebSocketHandler {
|
||||
if("done".equals(resultFlag)){
|
||||
log.info("1、开始处理时间:{}",System.currentTimeMillis()/1000);
|
||||
// //开始合并语音流
|
||||
// List<byte[]> fragments = fragmentCache.get(clientId);
|
||||
// // 合并所有分片为完整语音数据
|
||||
// byte[] fullVoiceData = mergeFragments(fragments);
|
||||
// // 生成唯一文件名
|
||||
// String fileName = clientId + "_" + System.currentTimeMillis() + ".webm";
|
||||
// String pathUrl = RuoYiConfig.getProfile()+VOICE_STORAGE_DIR + fileName;
|
||||
// log.info("文件路径为:{}", pathUrl);
|
||||
// log.info("文件流的大小为:{}",fullVoiceData.length);
|
||||
// saveAsWebM(fullVoiceData,pathUrl);
|
||||
// //开始转换
|
||||
// WhisperClient whisperClient = SpringUtils.getBean(WhisperClient.class);
|
||||
// String cacheResultText = whisperClient.handleVoiceToText(pathUrl);
|
||||
|
||||
//发送消息
|
||||
WebSocket webSocket = cacheWebSocket.get(clientId);
|
||||
if(webSocket != null){
|
||||
|
||||
}
|
||||
webSocket.send("{\"type\": \"input_audio_buffer.commit\"}");
|
||||
webSocket.send("{\"type\": \"response.create\"}");
|
||||
// if(webSocket != null){
|
||||
// webSocket.close(1000,null);
|
||||
// }
|
||||
|
||||
//语音结束,开始进行回答解析
|
||||
String cacheResultText = cacheClientTts.get(clientId);
|
||||
log.info("返回的结果为:{}",cacheResultText);
|
||||
@@ -247,30 +217,14 @@ public class ChatWebSocketHandler {
|
||||
|
||||
}
|
||||
|
||||
// 接收二进制消息(流数据)
|
||||
// @OnMessage
|
||||
// public void onBinaryMessage(Session session, @PathParam("clientId") String clientId, ByteBuffer byteBuffer) {
|
||||
// log.info("1、开始接收数据流时间:{}",System.currentTimeMillis()/1000);
|
||||
// log.info("客户端ID为:{}", clientId);
|
||||
// // 处理二进制流数据
|
||||
// byte[] bytes = new byte[byteBuffer.remaining()];
|
||||
// //从缓冲区中读取数据并存储到指定的字节数组中
|
||||
// byteBuffer.get(bytes);
|
||||
//
|
||||
// // 1. 获取当前会话的缓存
|
||||
// List<byte[]> fragments = fragmentCache.get(clientId);
|
||||
// if (fragments == null) {
|
||||
// fragments = new ArrayList<>();
|
||||
// fragmentCache.put(clientId, fragments);
|
||||
// }
|
||||
// fragments.add(bytes);
|
||||
// fragmentCache.put(clientId, fragments);
|
||||
// }
|
||||
|
||||
// 连接关闭时调用
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason reason) {
|
||||
System.out.println("WebSocket连接已关闭: " + session.getId() + ", 原因: " + reason.getReasonPhrase());
|
||||
// WebSocket webSocket = cacheWebSocket.get(clientId);
|
||||
// if(webSocket != null){
|
||||
// webSocket.close(1000,null);
|
||||
// }
|
||||
}
|
||||
|
||||
// 发生错误时调用
|
||||
@@ -293,17 +247,10 @@ public class ChatWebSocketHandler {
|
||||
System.err.println("字节数组为空,无法生成WebM文件");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filePath == null || filePath.trim().isEmpty()) {
|
||||
System.err.println("文件路径不能为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保文件以.webm结尾
|
||||
// if (!filePath.toLowerCase().endsWith(".webm")) {
|
||||
// filePath += ".webm";
|
||||
// }
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(filePath);
|
||||
@@ -349,7 +296,6 @@ public class ChatWebSocketHandler {
|
||||
private void createWhisperRealtimeSocket(String clientId){
|
||||
try{
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
// CountDownLatch latch = new CountDownLatch(1);
|
||||
// 设置 WebSocket 请求
|
||||
Request request = new Request.Builder()
|
||||
.url(API_URL)
|
||||
@@ -419,33 +365,11 @@ public class ChatWebSocketHandler {
|
||||
// latch.countDown();
|
||||
}
|
||||
});
|
||||
// 等待 WebSocket 关闭
|
||||
// latch.await();
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 合并分片数组为完整字节数组
|
||||
*/
|
||||
private byte[] mergeFragments(List<byte[]> fragments) {
|
||||
// 计算总长度
|
||||
int totalLength = 0;
|
||||
for (byte[] fragment : fragments) {
|
||||
totalLength += fragment.length;
|
||||
}
|
||||
// 拼接所有分片
|
||||
byte[] result = new byte[totalLength];
|
||||
int offset = 0;
|
||||
for (byte[] fragment : fragments) {
|
||||
System.arraycopy(fragment, 0, result, offset, fragment.length);
|
||||
offset += fragment.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音流文件格式转换
|
||||
* @param pathUrl
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.vetti.web.controller.system;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -30,6 +33,7 @@ import com.vetti.system.service.ISysDictTypeService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="数据字典信息模块")
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/data")
|
||||
public class SysDictDataController extends BaseController
|
||||
@@ -62,9 +66,10 @@ public class SysDictDataController extends BaseController
|
||||
/**
|
||||
* 查询字典数据详细
|
||||
*/
|
||||
@ApiOperation("查询字典数据详细")
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictCode}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictCode)
|
||||
public AjaxResult<SysDictData> getInfo(@PathVariable Long dictCode)
|
||||
{
|
||||
return success(dictDataService.selectDictDataById(dictCode));
|
||||
}
|
||||
@@ -72,8 +77,9 @@ public class SysDictDataController extends BaseController
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@ApiOperation("根据字典类型查询字典数据信息")
|
||||
@GetMapping(value = "/type/{dictType}")
|
||||
public AjaxResult dictType(@PathVariable String dictType)
|
||||
public AjaxResult<List<SysDictData>> dictType(@PathVariable String dictType)
|
||||
{
|
||||
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
|
||||
if (StringUtils.isNull(data))
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import com.vetti.common.utils.MessageUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -29,6 +31,7 @@ import com.vetti.system.service.ISysMenuService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="登录模块")
|
||||
@RestController
|
||||
public class SysLoginController
|
||||
{
|
||||
@@ -53,6 +56,7 @@ public class SysLoginController
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiOperation("登录方法")
|
||||
@PostMapping("/login")
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
@@ -69,6 +73,7 @@ public class SysLoginController
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
@ApiOperation("获取用户信息")
|
||||
@GetMapping("getInfo")
|
||||
public AjaxResult getInfo()
|
||||
{
|
||||
@@ -84,11 +89,13 @@ public class SysLoginController
|
||||
tokenService.refreshToken(loginUser);
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", roles);
|
||||
ajax.put("permissions", permissions);
|
||||
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
Map mapInfo = new HashMap();
|
||||
mapInfo.put("user", user);
|
||||
mapInfo.put("roles", roles);
|
||||
mapInfo.put("permissions", permissions);
|
||||
mapInfo.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
mapInfo.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
ajax.put("data", mapInfo);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
@@ -97,6 +104,7 @@ public class SysLoginController
|
||||
*
|
||||
* @return 路由信息
|
||||
*/
|
||||
@ApiOperation("获取路由信息")
|
||||
@GetMapping("getRouters")
|
||||
public AjaxResult getRouters()
|
||||
{
|
||||
@@ -128,4 +136,19 @@ public class SysLoginController
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiOperation("忘记密码")
|
||||
@PostMapping("/forgotPassword")
|
||||
public AjaxResult handlePassword(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
loginService.resetPassword(loginBody.getUsername(),loginBody.getPassword(),loginBody.getRepeatPassword(),loginBody.getCode(),loginBody.getUuid());
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemCommonTip10001"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -16,23 +18,19 @@ import com.vetti.system.service.ISysConfigService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="注册验证模块")
|
||||
@RestController
|
||||
public class SysRegisterController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private SysRegisterService registerService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@ApiOperation("注册方法")
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody RegisterBody user)
|
||||
{
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import com.vetti.common.core.controller.BaseController;
|
||||
import com.vetti.common.core.domain.AjaxResult;
|
||||
import com.vetti.common.service.verification.VerificationService;
|
||||
import com.vetti.common.utils.MessageUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/8/28 16:16
|
||||
*/
|
||||
@Api(tags ="验证码共通接口")
|
||||
@RestController
|
||||
@RequestMapping("/verification")
|
||||
@RequiredArgsConstructor
|
||||
public class VerificationController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private final VerificationService verificationEmailService;
|
||||
|
||||
|
||||
@ApiOperation("发送验证码(标题、内容走的配置文件)")
|
||||
@PostMapping("/email/send")
|
||||
public AjaxResult sendVerificationCode(@RequestParam String email) {
|
||||
boolean isSent = verificationEmailService.sendVerificationEm7941VerificationCode(email);
|
||||
if (isSent) {
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10001"));
|
||||
} else {
|
||||
return AjaxResult.error(MessageUtils.messageCustomize("systemVerificationEmailController10002"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮箱验证码
|
||||
*/
|
||||
@PostMapping("/email/verify")
|
||||
public AjaxResult verifyCode(@RequestParam String email, @RequestParam String code) {
|
||||
boolean isValid = verificationEmailService.verifyCode(email, code);
|
||||
if (isValid) {
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10003"));
|
||||
} else {
|
||||
return AjaxResult.error(MessageUtils.messageCustomize("systemVerificationEmailController10004"));
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("发送验证码(手机)")
|
||||
@PostMapping("/phone/send")
|
||||
public AjaxResult sendPhoneVerificationCode(@RequestParam String phone) {
|
||||
verificationEmailService.sendPhoneVerificationCode(phone);
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10003"));
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,10 @@ twilio:
|
||||
from-name: RouteZ
|
||||
template-ids:
|
||||
routez-verification-code: d-321fee8a85704983849eb1f69313ae24
|
||||
accountSID: 1111
|
||||
authToken: 22222
|
||||
sendPhoneNumber: 33333
|
||||
|
||||
verification:
|
||||
code:
|
||||
email:
|
||||
@@ -148,6 +152,7 @@ elevenLabs:
|
||||
# apiKey: sk_5240d8f56cb1eb5225fffcf903f62479884d1af5b3de6812
|
||||
apiKey: sk_88f5a560e1bbde0e5b8b6b6eb1812163a98bfb98554acbec
|
||||
modelId: eleven_turbo_v2_5
|
||||
|
||||
# 语音转文本
|
||||
whisper:
|
||||
apiUrl: https://api.openai.com/v1/audio/transcriptions
|
||||
|
||||
@@ -37,6 +37,21 @@ systemVerificationEmailController10004 = The Verification Code Is Invalid Or Has
|
||||
|
||||
SystemCommandOverhaulAppController10001 = Operation Successful
|
||||
|
||||
|
||||
systemSysLoginService10001 = The username cannot be empty
|
||||
systemSysLoginService10002 = User password cannot be empty
|
||||
systemSysLoginService10003 = User does not exist
|
||||
systemSysLoginService10004 = Passwords do not match
|
||||
|
||||
systemSysRegisterService10001 = The username cannot be empty
|
||||
systemSysRegisterService10002 = User password cannot be empty
|
||||
systemSysRegisterService10003 = The account length must be between 2 and 20 characters
|
||||
systemSysRegisterService10004 = The password length must be between 5 and 20 characters
|
||||
systemSysRegisterService10005 = Save User
|
||||
systemSysRegisterService10006 = Failed, registered account already exists
|
||||
systemSysRegisterService10007 = Registration failed, please contact the system administrator
|
||||
|
||||
|
||||
systemEmailUtil10001 = Sending Email Failed
|
||||
systemR10001 = Operation Successful
|
||||
|
||||
|
||||
@@ -37,6 +37,19 @@ systemVerificationEmailController10004 = 验证码无效或已过期
|
||||
|
||||
SystemCommandOverhaulAppController10001 = 操作成功
|
||||
|
||||
systemSysLoginService10001 = 用户名不能为空
|
||||
systemSysLoginService10002 = 用户密码不能为空
|
||||
systemSysLoginService10003 = 用户不存在
|
||||
systemSysLoginService10004 = 密码不一致
|
||||
|
||||
systemSysRegisterService10001 = 用户名不能为空
|
||||
systemSysRegisterService10002 = 用户密码不能为空
|
||||
systemSysRegisterService10003 = 账户长度必须在2到20个字符之间
|
||||
systemSysRegisterService10004 = 密码长度必须在5到20个字符之间
|
||||
systemSysRegisterService10005 = 保存用户
|
||||
systemSysRegisterService10006 = 失败,注册账号已存在
|
||||
systemSysRegisterService10007 = 注册失败,请联系系统管理人员
|
||||
|
||||
systemEmailUtil10001 = 发送邮件失败
|
||||
systemR10001 = 操作成功
|
||||
|
||||
|
||||
@@ -135,6 +135,10 @@ twilio:
|
||||
from-name: RouteZ
|
||||
template-ids:
|
||||
routez-verification-code: d-321fee8a85704983849eb1f69313ae24
|
||||
accountSID: 1111
|
||||
authToken: 22222
|
||||
sendPhoneNumber: 33333
|
||||
|
||||
verification:
|
||||
code:
|
||||
email:
|
||||
@@ -148,6 +152,7 @@ elevenLabs:
|
||||
# apiKey: sk_5240d8f56cb1eb5225fffcf903f62479884d1af5b3de6812
|
||||
apiKey: sk_88f5a560e1bbde0e5b8b6b6eb1812163a98bfb98554acbec
|
||||
modelId: eleven_turbo_v2_5
|
||||
|
||||
# 语音转文本
|
||||
whisper:
|
||||
apiUrl: https://api.openai.com/v1/audio/transcriptions
|
||||
|
||||
@@ -37,6 +37,21 @@ systemVerificationEmailController10004 = The Verification Code Is Invalid Or Has
|
||||
|
||||
SystemCommandOverhaulAppController10001 = Operation Successful
|
||||
|
||||
|
||||
systemSysLoginService10001 = The username cannot be empty
|
||||
systemSysLoginService10002 = User password cannot be empty
|
||||
systemSysLoginService10003 = User does not exist
|
||||
systemSysLoginService10004 = Passwords do not match
|
||||
|
||||
systemSysRegisterService10001 = The username cannot be empty
|
||||
systemSysRegisterService10002 = User password cannot be empty
|
||||
systemSysRegisterService10003 = The account length must be between 2 and 20 characters
|
||||
systemSysRegisterService10004 = The password length must be between 5 and 20 characters
|
||||
systemSysRegisterService10005 = Save User
|
||||
systemSysRegisterService10006 = Failed, registered account already exists
|
||||
systemSysRegisterService10007 = Registration failed, please contact the system administrator
|
||||
|
||||
|
||||
systemEmailUtil10001 = Sending Email Failed
|
||||
systemR10001 = Operation Successful
|
||||
|
||||
|
||||
@@ -37,6 +37,19 @@ systemVerificationEmailController10004 = 验证码无效或已过期
|
||||
|
||||
SystemCommandOverhaulAppController10001 = 操作成功
|
||||
|
||||
systemSysLoginService10001 = 用户名不能为空
|
||||
systemSysLoginService10002 = 用户密码不能为空
|
||||
systemSysLoginService10003 = 用户不存在
|
||||
systemSysLoginService10004 = 密码不一致
|
||||
|
||||
systemSysRegisterService10001 = 用户名不能为空
|
||||
systemSysRegisterService10002 = 用户密码不能为空
|
||||
systemSysRegisterService10003 = 账户长度必须在2到20个字符之间
|
||||
systemSysRegisterService10004 = 密码长度必须在5到20个字符之间
|
||||
systemSysRegisterService10005 = 保存用户
|
||||
systemSysRegisterService10006 = 失败,注册账号已存在
|
||||
systemSysRegisterService10007 = 注册失败,请联系系统管理人员
|
||||
|
||||
systemEmailUtil10001 = 发送邮件失败
|
||||
systemR10001 = 操作成功
|
||||
|
||||
|
||||
@@ -143,18 +143,22 @@
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sendgrid</groupId>
|
||||
<artifactId>sendgrid-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
@@ -175,6 +179,11 @@
|
||||
<artifactId>tomcat-embed-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twilio.sdk</groupId>
|
||||
<artifactId>twilio</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ public class TwilioConfig {
|
||||
private String apiKey;
|
||||
private String fromEmail;
|
||||
private String fromName;
|
||||
private String fromEmailEm7941;
|
||||
private String fromNameEm7941;
|
||||
private String replyToEm7941;
|
||||
private TemplateIds templateIds;
|
||||
|
||||
|
||||
|
||||
@@ -83,8 +83,9 @@ public class BaseController
|
||||
{
|
||||
TableDataInfo rspData = new TableDataInfo();
|
||||
rspData.setCode(HttpStatus.SUCCESS);
|
||||
rspData.setMsg("查询成功");
|
||||
rspData.setRows(list);
|
||||
rspData.setSuccess(true);
|
||||
rspData.setMessage("查询成功");
|
||||
rspData.setDatas(list);
|
||||
rspData.setTotal(new PageInfo(list).getTotal());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.vetti.common.core.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.vetti.common.constant.HttpStatus;
|
||||
import com.vetti.common.utils.StringUtils;
|
||||
|
||||
@@ -18,11 +20,23 @@ public class AjaxResult<T> extends HashMap<String, Object>
|
||||
public static final String CODE_TAG = "code";
|
||||
|
||||
/** 返回内容 */
|
||||
public static final String MSG_TAG = "msg";
|
||||
public static final String MSG_TAG = "message";
|
||||
|
||||
/** 数据对象 */
|
||||
public static final String DATA_TAG = "data";
|
||||
|
||||
/**
|
||||
* 请求返回时间
|
||||
*/
|
||||
public static final String DATE_TIME = "timestamp";
|
||||
|
||||
/**
|
||||
* 成功状态标识
|
||||
*/
|
||||
public static final String SUCCESS = "success";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
|
||||
*/
|
||||
@@ -40,6 +54,12 @@ public class AjaxResult<T> extends HashMap<String, Object>
|
||||
{
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
super.put(DATE_TIME, DateUtil.now());
|
||||
if(HttpStatus.SUCCESS == code){
|
||||
super.put(SUCCESS, true);
|
||||
}else {
|
||||
super.put(SUCCESS, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,10 +73,17 @@ public class AjaxResult<T> extends HashMap<String, Object>
|
||||
{
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
super.put(DATE_TIME, DateUtil.now());
|
||||
if(HttpStatus.SUCCESS == code){
|
||||
super.put(SUCCESS, true);
|
||||
}else {
|
||||
super.put(SUCCESS, false);
|
||||
}
|
||||
if (StringUtils.isNotNull(data))
|
||||
{
|
||||
super.put(DATA_TAG, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,25 +1,38 @@
|
||||
package com.vetti.common.core.domain.model;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户登录对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class LoginBody
|
||||
{
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@ApiModelProperty("用户名")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
@ApiModelProperty("用户密码")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 确认密码
|
||||
*/
|
||||
@ApiModelProperty("确认密码")
|
||||
private String repeatPassword;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
@ApiModelProperty("验证码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
@@ -27,43 +40,4 @@ public class LoginBody
|
||||
*/
|
||||
private String uuid;
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getUuid()
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid)
|
||||
{
|
||||
this.uuid = uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,18 @@ public class TableDataInfo implements Serializable
|
||||
private long total;
|
||||
|
||||
/** 列表数据 */
|
||||
private List<?> rows;
|
||||
private List<?> datas;
|
||||
|
||||
/** 消息状态码 */
|
||||
private int code;
|
||||
|
||||
/** 消息内容 */
|
||||
private String msg;
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 成功标识
|
||||
*/
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 表格数据对象
|
||||
@@ -39,7 +44,7 @@ public class TableDataInfo implements Serializable
|
||||
*/
|
||||
public TableDataInfo(List<?> list, long total)
|
||||
{
|
||||
this.rows = list;
|
||||
this.datas = list;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
@@ -53,14 +58,14 @@ public class TableDataInfo implements Serializable
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public List<?> getRows()
|
||||
public List<?> getDatas()
|
||||
{
|
||||
return rows;
|
||||
return datas;
|
||||
}
|
||||
|
||||
public void setRows(List<?> rows)
|
||||
public void setDatas(List<?> rows)
|
||||
{
|
||||
this.rows = rows;
|
||||
this.datas = rows;
|
||||
}
|
||||
|
||||
public int getCode()
|
||||
@@ -73,13 +78,21 @@ public class TableDataInfo implements Serializable
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg()
|
||||
public String getMessage()
|
||||
{
|
||||
return msg;
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMsg(String msg)
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.msg = msg;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Boolean getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(Boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 坐标
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 15:14
|
||||
*/
|
||||
@Data
|
||||
public class HereMapCoordinates {
|
||||
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
private String address;
|
||||
private String latlng;
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/1 21:56
|
||||
*/
|
||||
@Data
|
||||
public class HereMapLocationDto {
|
||||
private String title;
|
||||
private String address;
|
||||
private String city;
|
||||
private String country;
|
||||
private String postalCode;
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
|
||||
public HereMapLocationDto() {
|
||||
}
|
||||
|
||||
|
||||
public HereMapLocationDto(String address, String city, String country, String postalCode, double latitude, double longitude) {
|
||||
this.address = address;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.postalCode = postalCode;
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public HereMapLocationDto(String title, String address, double latitude, double longitude) {
|
||||
this.title = title;
|
||||
this.address = address;
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap;
|
||||
|
||||
import com.vetti.common.entity.hereMap.vehicle.HereMapVehicleTruck;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 16:40
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRouteVo {
|
||||
|
||||
// 基本路线参数
|
||||
private HereMapCoordinates origin; // 起点坐标 (纬度,经度)
|
||||
private HereMapCoordinates destination; // 终点坐标 (纬度,经度)
|
||||
private List<HereMapCoordinates> via; // 途径点坐标列表 (纬度,经度)
|
||||
private String transportMode; // 运输方式
|
||||
private List<String> avoid; // 避开选项
|
||||
|
||||
private String routingMode; // 路线偏好
|
||||
|
||||
private String returnStr = "polyline,actions,instructions,summary,travelSummary,typicalDuration,turnByTurnActions,elevation,routeHandle,passthrough,incidents,routingZones,truckRoadTypes,tolls,routeLabels,potentialTimeDependentViolations,noThroughRestrictions"; // 路线偏好
|
||||
private String lang; // 语言
|
||||
private String units; // 单位("metric" "imperial" 枚举:“公制”“英制”)
|
||||
|
||||
private String departureTime; // 开始时间
|
||||
private String arrivalTime; // 结束时间
|
||||
|
||||
|
||||
private HereMapVehicleTruck vehicle;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 16:40
|
||||
*/
|
||||
@Data
|
||||
public class HereMapTruckRoute {
|
||||
|
||||
// 基本路线参数
|
||||
private String start; // 起点坐标 (纬度,经度)
|
||||
private String end; // 终点坐标 (纬度,经度)
|
||||
private String routePreference; // 路线偏好: fastest, shortest, balanced
|
||||
|
||||
// 车辆基本参数
|
||||
private Integer height; // 高度(厘米)
|
||||
private Integer width; // 宽度(厘米)
|
||||
private Integer length; // 长度(厘米)
|
||||
private Integer weightTotal; // 总重量(KG)
|
||||
|
||||
// 避开选项
|
||||
private boolean avoidHighways; // 避开高速公路
|
||||
private boolean avoidTolls; // 避开收费道路
|
||||
private boolean avoidFerries; // 避开轮渡
|
||||
private boolean avoidTunnels; // 避开隧道
|
||||
private boolean avoidDifficultTurns; // 避开掉头
|
||||
private boolean avoidDirtRoads; // 避开土路
|
||||
|
||||
// 危化品参数
|
||||
private boolean hazmatExplosive;
|
||||
private boolean hazmatGas;
|
||||
private boolean hazmatFlammable;
|
||||
private boolean hazmatCombustible;
|
||||
private boolean hazmatOrganic;
|
||||
private boolean hazmatPoison;
|
||||
private boolean hazmatRadioactive;
|
||||
private boolean hazmatCorrosive;
|
||||
private boolean hazmatPoisonousInhalation;
|
||||
private boolean hazmatHarmfulToWater;
|
||||
private boolean hazmatOther;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.queryParam;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/5 23:55
|
||||
*/
|
||||
public abstract class BaseHereMapQueryParamVehicle {
|
||||
|
||||
private Integer height;//高 cm
|
||||
|
||||
private Integer width;//宽 cm
|
||||
|
||||
private Integer length;//长 cm
|
||||
|
||||
private Integer payloadCapacity;//载重 kg
|
||||
|
||||
private String shippedHazardousGoods;//危化品
|
||||
|
||||
protected HereMapQueryParam getHeight(Integer height) {
|
||||
return HereMapQueryParam.build("vehicle[height]", height);
|
||||
}
|
||||
|
||||
protected HereMapQueryParam getWidth(Integer width) {
|
||||
return HereMapQueryParam.build("vehicle[width]", width);
|
||||
}
|
||||
|
||||
protected HereMapQueryParam getLength(Integer length) {
|
||||
return HereMapQueryParam.build("vehicle[length]", length);
|
||||
}
|
||||
|
||||
protected HereMapQueryParam getPayloadCapacity(Integer payloadCapacity) {
|
||||
return HereMapQueryParam.build("vehicle[payloadCapacity]", payloadCapacity);
|
||||
}
|
||||
|
||||
protected HereMapQueryParam getShippedHazardousGoods(String shippedHazardousGoods) {
|
||||
return HereMapQueryParam.build("vehicle[shippedHazardousGoods]", shippedHazardousGoods);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.queryParam;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 22:03
|
||||
*/
|
||||
@Data
|
||||
public class HereMapQueryParam {
|
||||
|
||||
private String key;
|
||||
private Object value;
|
||||
|
||||
public static HereMapQueryParam build(String key, Object value) {
|
||||
HereMapQueryParam data = new HereMapQueryParam();
|
||||
data.setKey(key);
|
||||
data.setValue(value);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.queryParam;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/5 23:55
|
||||
*/
|
||||
public class HereMapQueryParamTruck extends BaseHereMapQueryParamVehicle{
|
||||
|
||||
public HereMapQueryParam getHeight(Integer height) {
|
||||
return super.getHeight(height);
|
||||
}
|
||||
|
||||
public HereMapQueryParam getWidth(Integer width) {
|
||||
return super.getWidth(width);
|
||||
}
|
||||
|
||||
public HereMapQueryParam getLength(Integer length) {
|
||||
return super.getLength(length);
|
||||
}
|
||||
|
||||
public HereMapQueryParam getPayloadCapacity(Integer payloadCapacity) {
|
||||
return super.getPayloadCapacity(payloadCapacity);
|
||||
}
|
||||
|
||||
public HereMapQueryParam getShippedHazardousGoods(String shippedHazardousGoods) {
|
||||
return super.getShippedHazardousGoods(shippedHazardousGoods);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 基础导航动作(含中文指令)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:44
|
||||
*/
|
||||
@Data
|
||||
public class HereMapAction {
|
||||
|
||||
/**
|
||||
* 动作类型(depart/turn/continue/arrive)
|
||||
*/
|
||||
private String action;
|
||||
/**
|
||||
* 动作耗时(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
/**
|
||||
* 动作距离(米)
|
||||
*/
|
||||
private Integer length;
|
||||
/**
|
||||
* 中文导航指令(如"沿着 Bluegum Pl 朝 Alison St 行驶")
|
||||
*/
|
||||
private String instruction;
|
||||
/**
|
||||
* 偏移量(路线中的位置索引)
|
||||
*/
|
||||
private Integer offset;
|
||||
/**
|
||||
* 转向方向(仅turn动作有值:left/right)
|
||||
*/
|
||||
private String direction;
|
||||
/**
|
||||
* 转向强度(仅turn动作有值:quite)
|
||||
*/
|
||||
private String severity;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 到达信息
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:55
|
||||
*/
|
||||
@Data
|
||||
public class HereMapArrival {
|
||||
|
||||
/**
|
||||
* 到达时间(ISO8601格式,如"2025-09-11T11:44:37+10:00")
|
||||
*/
|
||||
private String time;
|
||||
/**
|
||||
* 到达地点
|
||||
*/
|
||||
private HereMapPlace place;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 出发信息
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:54
|
||||
*/
|
||||
@Data
|
||||
public class HereMapDeparture {
|
||||
|
||||
/**
|
||||
* 出发时间(ISO8601格式,如"2025-09-11T11:27:17+10:00")
|
||||
*/
|
||||
private String time;
|
||||
/**
|
||||
* 出发地点
|
||||
*/
|
||||
private HereMapPlace place;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 坐标信息(经纬度、海拔)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:57
|
||||
*/
|
||||
@Data
|
||||
public class HereMapLocation {
|
||||
|
||||
/**
|
||||
* 纬度(如-33.7895301)
|
||||
*/
|
||||
private Double lat;
|
||||
/**
|
||||
* 经度(如151.16786)
|
||||
*/
|
||||
private Double lng;
|
||||
/**
|
||||
* 海拔(米,如70.0)
|
||||
*/
|
||||
private Double elv;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 通知信息(如计算提示、警告)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 15:02
|
||||
*/
|
||||
@Data
|
||||
public class HereMapNotice {
|
||||
|
||||
/**
|
||||
* 通知标题(如"Pre-conditions required for mlDuration calculation failed")
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 通知编码(如"mlDurationUnavailable")
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 通知级别(info/warn/error,此处为info)
|
||||
*/
|
||||
private String severity;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 地点信息(经纬度、海拔)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:56
|
||||
*/
|
||||
@Data
|
||||
public class HereMapPlace {
|
||||
|
||||
/**
|
||||
* 地点类型(固定为"place")
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 校正后坐标(含海拔)
|
||||
*/
|
||||
private HereMapLocation location;
|
||||
/**
|
||||
* 原始坐标(用户输入或初始定位)
|
||||
*/
|
||||
private HereMapLocation originalLocation;
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 道路信息(名称、编号、行驶方向)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:47
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRoadInfo {
|
||||
|
||||
/**
|
||||
* 道路名称列表(多语言,此处仅en)
|
||||
*/
|
||||
private List<HereMapRoadName> name;
|
||||
/**
|
||||
* 道路编号列表(如A1、A38,含路线类型)
|
||||
*/
|
||||
private List<HereMapRoadNumber> number;
|
||||
/**
|
||||
* 行驶方向列表(如"Frenchs Forest"、"City")
|
||||
*/
|
||||
private List<HereMapRoadToward> toward;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 道路名称(多语言支持)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:48
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRoadName {
|
||||
|
||||
/**
|
||||
* 道路名称(如"Bluegum Pl")
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 语言(固定为"en")
|
||||
*/
|
||||
private String language;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 道路编号(含路线类型)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:49
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRoadNumber {
|
||||
|
||||
/**
|
||||
* 道路编号(如"A1"、"A38")
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 语言(固定为"en")
|
||||
*/
|
||||
private String language;
|
||||
/**
|
||||
* 路线类型(固定为6,代表主干道)
|
||||
*/
|
||||
private Integer routeType;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 道路行驶方向
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:50
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRoadToward {
|
||||
|
||||
/**
|
||||
* 方向名称(如"Northbridge"、"Airport")
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 语言(固定为"en")
|
||||
*/
|
||||
private String language;
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单个路由信息
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:42
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRoute {
|
||||
|
||||
/**
|
||||
* 路由ID(如"6e1a8f39-d309-43d0-8b72-ab9b810af8b1")
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 路由分段列表(仅包含vehicle类型分段)
|
||||
*/
|
||||
private List<HereMapRouteSection> sections;
|
||||
/**
|
||||
* 路由标识(如道路名称、编号)
|
||||
*/
|
||||
private List<HereMapRouteLabel> routeLabels;
|
||||
/**
|
||||
* 路由句柄(编码字符串)
|
||||
*/
|
||||
private String routeHandle;
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 路由响应顶层实体
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:41
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRouteDto {
|
||||
|
||||
/**
|
||||
* 路由列表(JSON中的"routes"数组)
|
||||
*/
|
||||
private List<HereMapRoute> routes;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 路由标识(道路名称、编号)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:43
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRouteLabel {
|
||||
|
||||
/**
|
||||
* 标识类型(Name/RouteNumber)
|
||||
*/
|
||||
private String label_type;
|
||||
/**
|
||||
* 名称信息(如道路名称)
|
||||
*/
|
||||
private HereMapRoadName name;
|
||||
/**
|
||||
* 路线编号信息(如A38)
|
||||
*/
|
||||
private HereMapRoadNumber routeNumber;
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 路由分段(车辆行驶分段)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:42
|
||||
*/
|
||||
@Data
|
||||
public class HereMapRouteSection {
|
||||
|
||||
/**
|
||||
* 分段ID(如"7bed8aae-2ad3-4e74-8a11-0a2ae7eedc97")
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 分段类型(固定为"vehicle")
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 行驶动作列表(含中文导航指令)
|
||||
*/
|
||||
private List<HereMapAction> actions;
|
||||
/**
|
||||
* 详细转向动作列表(含道路信息、转向角度)
|
||||
*/
|
||||
private List<HereMapTurnByTurnAction> turnByTurnActions;
|
||||
/**
|
||||
* 出发信息(时间、地点)
|
||||
*/
|
||||
private HereMapDeparture departure;
|
||||
/**
|
||||
* 到达信息(时间、地点)
|
||||
*/
|
||||
private HereMapArrival arrival;
|
||||
/**
|
||||
* 分段概要(时长、距离等)
|
||||
*/
|
||||
private HereMapSummary summary;
|
||||
/**
|
||||
* 行程概要(与summary结构一致)
|
||||
*/
|
||||
private HereMapTravelSummary travelSummary;
|
||||
/**
|
||||
* 路线polyline编码(用于地图绘制)
|
||||
*/
|
||||
private String polyline;
|
||||
/**
|
||||
* 通知信息(如计算提示)
|
||||
*/
|
||||
private List<HereMapNotice> notices;
|
||||
/**
|
||||
* 语言(固定为"zh-cn")
|
||||
*/
|
||||
private String language;
|
||||
/**
|
||||
* 交通方式(固定为"car")
|
||||
*/
|
||||
private HereMapTransport transport;
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 路牌信息(导航标识)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:52
|
||||
*/
|
||||
@Data
|
||||
public class HereMapSignpost {
|
||||
|
||||
/**
|
||||
* 路牌标签列表(含道路名称、方向、编号)
|
||||
*/
|
||||
private List<HereMapSignpostLabel> labels;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 路牌标签(单个标识项)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:52
|
||||
*/
|
||||
@Data
|
||||
public class HereMapSignpostLabel {
|
||||
|
||||
/**
|
||||
* 名称标签(如道路名称、方向)
|
||||
*/
|
||||
private HereMapRoadName name;
|
||||
/**
|
||||
* 路线编号标签(如"A38")
|
||||
*/
|
||||
private HereMapRoadNumber routeNumber;
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 分段概要(时长、距离统计)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:59
|
||||
*/
|
||||
@Data
|
||||
public class HereMapSummary {
|
||||
|
||||
/**
|
||||
* 总耗时(秒,含交通延误)
|
||||
*/
|
||||
private Integer duration;
|
||||
/**
|
||||
* 总距离(米)
|
||||
*/
|
||||
private Integer length;
|
||||
/**
|
||||
* 基础耗时(秒,不含交通延误)
|
||||
*/
|
||||
private Integer baseDuration;
|
||||
/**
|
||||
* 典型耗时(秒,历史平均耗时)
|
||||
*/
|
||||
private Integer typicalDuration;
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 交通方式
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 15:03
|
||||
*/
|
||||
@Data
|
||||
public class HereMapTransport {
|
||||
|
||||
/**
|
||||
* 交通模式(固定为"car")
|
||||
*/
|
||||
private String mode;
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 行程概要(与Summary结构完全一致)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 15:00
|
||||
*/
|
||||
@Data
|
||||
public class HereMapTravelSummary {
|
||||
|
||||
/**
|
||||
* 总耗时(秒,含交通延误)
|
||||
*/
|
||||
private Integer duration;
|
||||
/**
|
||||
* 总距离(米)
|
||||
*/
|
||||
private Integer length;
|
||||
/**
|
||||
* 基础耗时(秒,不含交通延误)
|
||||
*/
|
||||
private Integer baseDuration;
|
||||
/**
|
||||
* 典型耗时(秒,历史平均耗时)
|
||||
*/
|
||||
private Integer typicalDuration;
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.route;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 详细转向动作(含道路信息、转向角度)
|
||||
*
|
||||
* @author ID
|
||||
* @date 2025/9/11 14:46
|
||||
*/
|
||||
@Data
|
||||
public class HereMapTurnByTurnAction {
|
||||
|
||||
/**
|
||||
* 动作类型(同Action的action字段)
|
||||
*/
|
||||
private String action;
|
||||
/**
|
||||
* 动作耗时(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
/**
|
||||
* 动作距离(米)
|
||||
*/
|
||||
private Integer length;
|
||||
/**
|
||||
* 偏移量(路线中的位置索引)
|
||||
*/
|
||||
private Integer offset;
|
||||
/**
|
||||
* 转向方向(仅turn动作有值:left/right)
|
||||
*/
|
||||
private String direction;
|
||||
/**
|
||||
* 转向强度(仅turn动作有值:quite)
|
||||
*/
|
||||
private String severity;
|
||||
/**
|
||||
* 当前道路信息(仅非depart动作有值)
|
||||
*/
|
||||
private HereMapRoadInfo currentRoad;
|
||||
/**
|
||||
* 下一条道路信息(仅非arrive动作有值)
|
||||
*/
|
||||
private HereMapRoadInfo nextRoad;
|
||||
/**
|
||||
* 转向角度(度,负值为左转,正值为右转)
|
||||
*/
|
||||
private Double turnAngle;
|
||||
/**
|
||||
* 路牌信息(含导航标识)
|
||||
*/
|
||||
private HereMapSignpost signpost;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.vehicle;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/12 9:33
|
||||
*/
|
||||
@Data
|
||||
public class HereMapVehicle {
|
||||
|
||||
private Integer height;//高 cm
|
||||
|
||||
private Integer width;//宽 cm
|
||||
|
||||
private Integer length;//长 cm
|
||||
|
||||
private Double speedCap;//最大速度 m/s
|
||||
|
||||
private Integer grossWeight;//车辆总重量,包括挂车和满载货物。 kg
|
||||
|
||||
private Integer currentWeight;//当前车辆总重量,包括挂车和满载货物。 kg
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.vetti.common.entity.hereMap.vehicle;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/12 9:33
|
||||
*/
|
||||
@Data
|
||||
public class HereMapVehicleTruck extends HereMapVehicle {
|
||||
|
||||
private Integer axleCount;//总轴数 指定车辆具有的轴的总数,即基础车辆上的轴和任何附加的拖车。
|
||||
private Integer trailerAxleCount;//拖车总轴数,不含车头 指定连接到车辆的所有拖车的轴总数。 这个数字包含在 axleCount 中,因此 trailerAxleCount 必须严格小于 axleCount 。 trailerCount 必须非零。
|
||||
private Integer weightPerAxle;//每轴最重车辆重量 kg 每轴最重车辆重量,单位为公斤。
|
||||
private Integer trailerCount;//拖车数量 与车辆相连的拖车的数量。
|
||||
private String type;//类型 StraightTruck:直车(单车架设计,载货区(如货箱)与车架永久固定,不可分离);Tractor:牵引车 / 拖拉机()仅为 “牵引车头”,无独立载货区,需通过牵引装置连接半挂车
|
||||
|
||||
private String cargoType;//货物类型 非here map 属性 normal:普通货物;hazardous:危险品
|
||||
private List<String> hazardousGoods;//危化品
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.vetti.common.service.hereMap;
|
||||
|
||||
import com.vetti.common.entity.hereMap.HereMapLocationDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface HereMapGeocoderService {
|
||||
|
||||
List<HereMapLocationDto> getCoordinates(String location);
|
||||
|
||||
HereMapLocationDto getLocationFromCoordinates(double latitude, double longitude);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.vetti.common.service.hereMap;
|
||||
|
||||
import com.vetti.common.entity.hereMap.HereMapRouteVo;
|
||||
import com.vetti.common.entity.hereMap.route.HereMapRouteDto;
|
||||
|
||||
public interface HereMapRoutingService {
|
||||
|
||||
HereMapRouteDto findRouting(HereMapRouteVo truckRoute);
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.vetti.common.service.hereMap.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.vetti.common.config.HereMapsProperties;
|
||||
import com.vetti.common.entity.hereMap.HereMapCoordinates;
|
||||
import com.vetti.common.entity.hereMap.queryParam.HereMapQueryParam;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 21:42
|
||||
*/
|
||||
@Log4j2
|
||||
public abstract class BaseHereMapsService {
|
||||
|
||||
@Resource
|
||||
protected HereMapsProperties hereMapsProperties;
|
||||
|
||||
@Resource
|
||||
protected HttpClient httpClient;
|
||||
|
||||
@Resource
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
@Value("${http.client.connect-timeout-seconds:10}")
|
||||
protected Integer connectTimeoutSeconds;
|
||||
|
||||
|
||||
/**
|
||||
* 构建HTTP请求
|
||||
*/
|
||||
protected HttpRequest buildHttpRequest(URI uri) {
|
||||
return HttpRequest.newBuilder()
|
||||
.uri(uri)
|
||||
.timeout(Duration.ofSeconds(connectTimeoutSeconds))
|
||||
.header("Accept", "application/json")
|
||||
.GET()
|
||||
.build();
|
||||
}
|
||||
|
||||
protected URI buildUri(String url, List<HereMapQueryParam> queryParams) throws Exception {
|
||||
String uriStr = url + "?" + hereMapQueryParamToStr(queryParams) + apiKey();
|
||||
return new URIBuilder(uriStr).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求并处理响应状态
|
||||
*/
|
||||
protected HttpResponse<String> sendHttpRequest(HttpRequest request) throws Exception {
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
if (statusCode != 200) {
|
||||
String errorMsg = String.format(
|
||||
"HERE Maps API请求失败:状态码=%d, 响应体=%s",
|
||||
statusCode, response.body()
|
||||
);
|
||||
log.error(errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全获取JSON节点文本,避免空指针
|
||||
*/
|
||||
protected String getOptionalNodeText(JsonNode parentNode, String fieldName) {
|
||||
JsonNode node = parentNode.get(fieldName);
|
||||
return (node != null && !node.isNull()) ? node.asText() : "";
|
||||
}
|
||||
|
||||
|
||||
private String apiKey() {
|
||||
return "apiKey=" + hereMapsProperties.getApiKey();
|
||||
}
|
||||
|
||||
private String hereMapQueryParamToStr(List<HereMapQueryParam> queryParams) {
|
||||
if (CollectionUtils.isNotEmpty(queryParams)) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
queryParams.forEach(e -> {
|
||||
if (e.getValue() instanceof HereMapCoordinates) {
|
||||
sb.append(e.getKey()).append("=").append(((HereMapCoordinates) e.getValue()).getLatlng()).append("&");
|
||||
} else {
|
||||
sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
|
||||
}
|
||||
});
|
||||
return sb.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package com.vetti.common.service.hereMap.impl;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.vetti.common.entity.hereMap.HereMapLocationDto;
|
||||
import com.vetti.common.entity.hereMap.queryParam.HereMapQueryParam;
|
||||
import com.vetti.common.exception.UtilException;
|
||||
import com.vetti.common.service.hereMap.HereMapGeocoderService;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 21:43
|
||||
*/
|
||||
@Log4j2
|
||||
@Service
|
||||
public class HereMapGeocoderServiceImpl extends BaseHereMapsService implements HereMapGeocoderService {
|
||||
|
||||
/**
|
||||
* 根据地点名称查询坐标
|
||||
*
|
||||
* @param location 地点名称(如"北京天安门")
|
||||
* @return 地点信息+坐标列表
|
||||
* @throws Exception 包含网络异常、API错误等
|
||||
*/
|
||||
@Override
|
||||
public List<HereMapLocationDto> getCoordinates(String location) {
|
||||
try {
|
||||
// 1. 参数校验
|
||||
if (location == null || location.trim().isEmpty()) {
|
||||
log.error("地点名称不能为空");
|
||||
throw new IllegalArgumentException("地点名称不能为空");
|
||||
}
|
||||
// 2. 构建请求URL
|
||||
List<HereMapQueryParam> queryParams = new ArrayList<>();
|
||||
String encodedLocation = URLEncoder.encode(location, StandardCharsets.UTF_8.name());
|
||||
queryParams.add(HereMapQueryParam.build("q", encodedLocation));
|
||||
// 3. 构建并发送HTTP请求
|
||||
URI requestUri = buildUri(hereMapsProperties.getGeocodingApiUrl(), queryParams);
|
||||
HttpRequest request = buildHttpRequest(requestUri);
|
||||
HttpResponse<String> response = sendHttpRequest(request);
|
||||
// 4. 处理响应并返回结果
|
||||
log.info("HERE Maps API请求成功,响应体长度:{} 字符", response.body().length());
|
||||
return parseGeocodingResponse(response.body());
|
||||
} catch (Exception e) {
|
||||
log.error("根据地点名称查询坐标信息失败", e);
|
||||
throw new UtilException("根据地点名称查询坐标信息失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取地理位置信息
|
||||
*
|
||||
* @param latitude 纬度(-90到90之间)
|
||||
* @param longitude 经度(-180到180之间)
|
||||
* @return 地理位置信息Optional
|
||||
*/
|
||||
@Override
|
||||
public HereMapLocationDto getLocationFromCoordinates(double latitude, double longitude) {
|
||||
try {
|
||||
// 1. 参数校验
|
||||
validateCoordinates(latitude, longitude);
|
||||
List<HereMapQueryParam> queryParams = new ArrayList<>();
|
||||
queryParams.add(HereMapQueryParam.build("at", latitude + "," + longitude));
|
||||
URI requestUri = buildUri(hereMapsProperties.getReverseGeocodingApiUrl(), queryParams);
|
||||
HttpRequest request = buildHttpRequest(requestUri);
|
||||
HttpResponse<String> response = sendHttpRequest(request);
|
||||
// 4. 处理响应并返回结果
|
||||
log.info("HERE Maps API请求成功,响应体长度:{} 字符", response.body().length());
|
||||
return parseLocationResponse(response.body(), latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("获取地理位置信息失败", e);
|
||||
throw new UtilException("获取地理位置信息失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析地理编码响应
|
||||
*/
|
||||
private List<HereMapLocationDto> parseGeocodingResponse(String responseBody) {
|
||||
List<HereMapLocationDto> results = new ArrayList<>();
|
||||
try {
|
||||
JsonNode rootNode = objectMapper.readTree(responseBody);
|
||||
JsonNode itemsNode = rootNode.get("items");
|
||||
if (itemsNode == null || !itemsNode.isArray() || itemsNode.size() == 0) {
|
||||
log.warn("地理编码无匹配结果");
|
||||
return results;
|
||||
}
|
||||
for (JsonNode item : itemsNode) {
|
||||
String title = item.get("title").asText();
|
||||
String address = item.get("address").get("label").asText();
|
||||
JsonNode position = item.get("position");
|
||||
double latitude = position.get("lat").asDouble();
|
||||
double longitude = position.get("lng").asDouble();
|
||||
results.add(new HereMapLocationDto(title, address, latitude, longitude));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析地理编码响应失败", e);
|
||||
throw new RuntimeException("解析地理编码结果失败", e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析逆地理编码响应
|
||||
*/
|
||||
private HereMapLocationDto parseLocationResponse(String responseBody, double latitude, double longitude) {
|
||||
try {
|
||||
JsonNode rootNode = objectMapper.readTree(responseBody);
|
||||
JsonNode itemsNode = rootNode.get("items");
|
||||
if (itemsNode != null && itemsNode.isArray() && itemsNode.size() > 0) {
|
||||
JsonNode firstItem = itemsNode.get(0);
|
||||
JsonNode addressNode = firstItem.get("address");
|
||||
HereMapLocationDto location = new HereMapLocationDto();
|
||||
location.setTitle(firstItem.get("title").asText());
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
location.setAddress(addressNode.get("label").asText());
|
||||
location.setCity(getOptionalNodeText(addressNode, "city"));
|
||||
location.setCountry(getOptionalNodeText(addressNode, "countryName"));
|
||||
location.setPostalCode(getOptionalNodeText(addressNode, "postalCode"));
|
||||
return location;
|
||||
}
|
||||
log.warn("逆地理编码无匹配结果");
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("解析逆地理编码响应失败", e);
|
||||
throw new RuntimeException("解析地理位置结果失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验经纬度合法性
|
||||
*/
|
||||
private void validateCoordinates(double latitude, double longitude) {
|
||||
if (latitude < -90 || latitude > 90) {
|
||||
log.error("纬度值不合法: {}", latitude);
|
||||
throw new IllegalArgumentException("纬度必须在-90到90之间");
|
||||
}
|
||||
if (longitude < -180 || longitude > 180) {
|
||||
log.error("经度值不合法: {}", longitude);
|
||||
throw new IllegalArgumentException("经度必须在-180到180之间");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
package com.vetti.common.service.hereMap.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.vetti.common.entity.hereMap.HereMapCoordinates;
|
||||
import com.vetti.common.entity.hereMap.HereMapRouteVo;
|
||||
import com.vetti.common.entity.hereMap.queryParam.HereMapQueryParam;
|
||||
import com.vetti.common.entity.hereMap.queryParam.HereMapQueryParamTruck;
|
||||
import com.vetti.common.entity.hereMap.route.HereMapRouteDto;
|
||||
import com.vetti.common.entity.hereMap.vehicle.HereMapVehicleTruck;
|
||||
import com.vetti.common.exception.ServiceException;
|
||||
import com.vetti.common.exception.UtilException;
|
||||
import com.vetti.common.service.hereMap.HereMapRoutingService;
|
||||
import com.vetti.common.utils.StringUtils;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/9/4 21:43
|
||||
*/
|
||||
@Log4j2
|
||||
@Service
|
||||
public class HereMapRoutingServiceImpl extends BaseHereMapsService implements HereMapRoutingService {
|
||||
|
||||
@Override
|
||||
public HereMapRouteDto findRouting(HereMapRouteVo truckRoute) {
|
||||
try {
|
||||
URI requestUri = buildRoutingUri(truckRoute);
|
||||
HttpRequest request = buildHttpRequest(requestUri);
|
||||
HttpResponse<String> response = sendHttpRequest(request);
|
||||
// 4. 处理响应并返回结果
|
||||
log.info("HERE Maps API请求成功,响应体长度:{} 字符", response.body().length());
|
||||
return parseRoutingResponse(response.body());
|
||||
} catch (Exception e) {
|
||||
log.error("获取地理位置信息失败", e);
|
||||
log.error("获取地理位置信息失败", e);
|
||||
throw new UtilException("获取地理位置信息失败");
|
||||
}
|
||||
}
|
||||
|
||||
private HereMapRouteDto parseRoutingResponse(String body) {
|
||||
if (StringUtils.isEmpty(body)) {
|
||||
return null;
|
||||
}
|
||||
return JSONObject.parseObject(body, HereMapRouteDto.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建路线规划请求URI
|
||||
*/
|
||||
private URI buildRoutingUri(HereMapRouteVo truckRoute) throws Exception {
|
||||
List<HereMapQueryParam> queryParams = new ArrayList<>();
|
||||
// 添加基本路线参数
|
||||
addBasicRoutingParameters(queryParams, truckRoute);
|
||||
// 添加车辆参数
|
||||
addTruckParameters(queryParams, truckRoute);
|
||||
|
||||
return buildUri(hereMapsProperties.getRouterApiUrl(), queryParams);
|
||||
}
|
||||
|
||||
private String queryParamsListToStr(List<String> list) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (String str : list) {
|
||||
sb.append(str).append(",");
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加基本路线参数
|
||||
*/
|
||||
private void addBasicRoutingParameters(List<HereMapQueryParam> queryParams, HereMapRouteVo truckRoute) {
|
||||
queryParams.add(HereMapQueryParam.build("origin", truckRoute.getOrigin()));
|
||||
queryParams.add(HereMapQueryParam.build("destination", truckRoute.getDestination()));
|
||||
if (CollectionUtils.isNotEmpty(truckRoute.getVia())) {
|
||||
for (HereMapCoordinates via : truckRoute.getVia()) {
|
||||
queryParams.add(HereMapQueryParam.build("via", via.getLatlng()));
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(truckRoute.getVia())) {
|
||||
queryParams.add(HereMapQueryParam.build("avoid[features]", queryParamsListToStr(truckRoute.getAvoid())));
|
||||
}
|
||||
|
||||
queryParams.add(HereMapQueryParam.build("transportMode", truckRoute.getTransportMode()));
|
||||
|
||||
queryParams.add(HereMapQueryParam.build("routingMode", truckRoute.getRoutingMode()));
|
||||
|
||||
if (StringUtils.isEmpty(truckRoute.getReturnStr())) {
|
||||
queryParams.add(HereMapQueryParam.build("return",
|
||||
"polyline,actions,instructions,summary,travelSummary,typicalDuration,turnByTurnActions,elevation,routeHandle,passthrough,incidents,routingZones,truckRoadTypes,tolls,routeLabels,potentialTimeDependentViolations,noThroughRestrictions"
|
||||
));
|
||||
} else {
|
||||
queryParams.add(HereMapQueryParam.build("return", truckRoute.getReturnStr()));
|
||||
}
|
||||
if (StringUtils.isEmpty(truckRoute.getLang())) {
|
||||
queryParams.add(HereMapQueryParam.build("lang", "zh-CN"));
|
||||
} else {
|
||||
queryParams.add(HereMapQueryParam.build("lang", truckRoute.getLang()));
|
||||
}
|
||||
if (StringUtils.isEmpty(truckRoute.getUnits())) {
|
||||
queryParams.add(HereMapQueryParam.build("units", "metric"));
|
||||
} else {
|
||||
queryParams.add(HereMapQueryParam.build("units", truckRoute.getUnits()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(truckRoute.getDepartureTime())) {
|
||||
queryParams.add(HereMapQueryParam.build("departureTime", truckRoute.getDepartureTime()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(truckRoute.getArrivalTime())) {
|
||||
queryParams.add(HereMapQueryParam.build("arrivalTime", truckRoute.getArrivalTime()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加车辆参数
|
||||
*/
|
||||
private void addTruckParameters(List<HereMapQueryParam> queryParams, HereMapRouteVo truckRoute) {
|
||||
HereMapQueryParamTruck hereMapQueryParamTruck = new HereMapQueryParamTruck();
|
||||
HereMapVehicleTruck vehicle = truckRoute.getVehicle();
|
||||
if (vehicle == null) {
|
||||
return;
|
||||
}
|
||||
if (vehicle.getHeight() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[height]", vehicle.getHeight()));
|
||||
}
|
||||
if (vehicle.getWidth() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[width]", vehicle.getWidth()));
|
||||
}
|
||||
if (vehicle.getLength() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[length]", vehicle.getLength()));
|
||||
}
|
||||
if (vehicle.getSpeedCap() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[speedCap]", vehicle.getSpeedCap()));
|
||||
}
|
||||
if (vehicle.getGrossWeight() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[grossWeight]", vehicle.getGrossWeight()));
|
||||
}
|
||||
if (vehicle.getCurrentWeight() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[currentWeight]", vehicle.getCurrentWeight()));
|
||||
}
|
||||
|
||||
if (vehicle.getAxleCount() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[axleCount]", vehicle.getAxleCount()));
|
||||
}
|
||||
if (vehicle.getTrailerAxleCount() != null) {
|
||||
if (vehicle.getAxleCount() >= 2 && (vehicle.getTrailerAxleCount() >= 1 && vehicle.getTrailerAxleCount() <= (vehicle.getAxleCount() - 1))) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[trailerAxleCount]", vehicle.getTrailerAxleCount()));
|
||||
} else {
|
||||
throw new ServiceException("区间trailerAxleCount:[1,(axleCount-1)]");
|
||||
}
|
||||
}
|
||||
if (vehicle.getWeightPerAxle() != null) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[weightPerAxle]", vehicle.getWeightPerAxle()));
|
||||
}
|
||||
if (vehicle.getTrailerCount() != null && (vehicle.getTrailerAxleCount() >= vehicle.getTrailerCount())) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[trailerCount]", vehicle.getTrailerCount()));
|
||||
}
|
||||
if (!StringUtils.isEmpty(vehicle.getType())) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[type]", vehicle.getType()));
|
||||
}
|
||||
if (!StringUtils.isEmpty(vehicle.getCargoType()) && "hazardous".equals(vehicle.getCargoType()) && CollectionUtils.isNotEmpty(vehicle.getHazardousGoods())) {
|
||||
queryParams.add(HereMapQueryParam.build("vehicle[shippedHazardousGoods]", String.join(",", vehicle.getHazardousGoods())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package com.vetti.common.service.verification;
|
||||
|
||||
import com.vetti.common.entity.verification.BaseTemplateEmail;
|
||||
|
||||
public interface VerificationEmailService {
|
||||
public interface VerificationService {
|
||||
|
||||
/**
|
||||
* 发送邮箱验证码(内容走的配置文件)
|
||||
@@ -20,6 +20,14 @@ public interface VerificationEmailService {
|
||||
*/
|
||||
boolean sendVerificationRoutezVerificationCode(String email);
|
||||
|
||||
/**
|
||||
* 使用 em7941.routez.app 域名发送验证码(官网模板)
|
||||
*
|
||||
* @param email 收件人邮箱
|
||||
* @return
|
||||
*/
|
||||
boolean sendVerificationEm7941VerificationCode(String email);
|
||||
|
||||
/**
|
||||
* 发动邮箱验证码 (内容走的官网配置模板)
|
||||
*
|
||||
@@ -39,4 +47,13 @@ public interface VerificationEmailService {
|
||||
* @return
|
||||
*/
|
||||
boolean verifyCode(String email, String code);
|
||||
|
||||
/**
|
||||
* 发送手机验证码
|
||||
*
|
||||
* @param phone 收件人手机号
|
||||
* @return
|
||||
*/
|
||||
void sendPhoneVerificationCode(String phone);
|
||||
|
||||
}
|
||||
@@ -6,9 +6,10 @@ import com.vetti.common.constant.CacheConstants;
|
||||
import com.vetti.common.core.redis.RedisCache;
|
||||
import com.vetti.common.entity.verification.BaseTemplateEmail;
|
||||
import com.vetti.common.entity.verification.RoutezVerificationCodeTemplate;
|
||||
import com.vetti.common.service.verification.VerificationEmailService;
|
||||
import com.vetti.common.service.verification.VerificationService;
|
||||
import com.vetti.common.utils.MessageUtils;
|
||||
import com.vetti.common.utils.email.EmailUtil;
|
||||
import com.vetti.common.utils.sms.TwilioSmsUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -21,7 +22,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* @date 2025/9/4 16:49
|
||||
*/
|
||||
@Service
|
||||
public class VerificationEmailServiceImpl implements VerificationEmailService {
|
||||
public class VerificationServiceImpl implements VerificationService {
|
||||
|
||||
@Resource
|
||||
private TwilioConfig twilioConfig;
|
||||
@@ -32,6 +33,9 @@ public class VerificationEmailServiceImpl implements VerificationEmailService {
|
||||
@Resource
|
||||
private EmailUtil emailUtil;
|
||||
|
||||
@Resource
|
||||
private TwilioSmsUtil twilioSmsUtil;
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
@@ -66,6 +70,27 @@ public class VerificationEmailServiceImpl implements VerificationEmailService {
|
||||
twilioConfig.getTemplateIds().getRoutezVerificationCode(), template);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 em7941.routez.app 域名发送验证码(官网模板)
|
||||
*/
|
||||
@Override
|
||||
public boolean sendVerificationEm7941VerificationCode(String email) {
|
||||
String code = generateVerificationCode();
|
||||
RoutezVerificationCodeTemplate template = new RoutezVerificationCodeTemplate();
|
||||
template.setVerification_code(code);
|
||||
template.setVerification_expiration(verificationConfig.getExpirationMinutes());
|
||||
try {
|
||||
redisCache.setCacheObject(CacheConstants.VERIFICATION_EMAIL_CODE_KEY + email, code,
|
||||
verificationConfig.getExpirationMinutes(), TimeUnit.MINUTES);
|
||||
emailUtil.sendEmailByEm7941(email, twilioConfig.getTemplateIds().getRoutezVerificationCode(), template);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// 记录日志
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发动邮箱验证码 (内容走的官网配置模板)
|
||||
*
|
||||
@@ -108,6 +133,16 @@ public class VerificationEmailServiceImpl implements VerificationEmailService {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPhoneVerificationCode(String phone){
|
||||
|
||||
String code = generateVerificationCode();
|
||||
redisCache.setCacheObject(CacheConstants.VERIFICATION_EMAIL_CODE_KEY + phone, code,
|
||||
verificationConfig.getExpirationMinutes(), TimeUnit.MINUTES);
|
||||
String msg = "验证码为:"+code;
|
||||
twilioSmsUtil.send(phone,msg);
|
||||
}
|
||||
|
||||
|
||||
private boolean sendVerificationCode(String email, String subject, String content) {
|
||||
String code = generateVerificationCode();
|
||||
@@ -13,6 +13,7 @@ import com.sendgrid.helpers.mail.Mail;
|
||||
import com.sendgrid.helpers.mail.objects.Content;
|
||||
import com.sendgrid.helpers.mail.objects.Email;
|
||||
import com.sendgrid.helpers.mail.objects.Personalization;
|
||||
import com.vetti.common.utils.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -111,4 +112,34 @@ public class EmailUtil {
|
||||
mail.addPersonalization(personalization);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 em7941.routez.app 域名发送模板邮件
|
||||
*/
|
||||
public void sendEmailByEm7941(String toEmail, String templateId, BaseTemplateEmail templateEmail) throws IOException {
|
||||
|
||||
Email from = new Email(twilioConfig.getFromEmailEm7941(), twilioConfig.getFromNameEm7941());
|
||||
Email to = new Email(toEmail);
|
||||
Content emailContent = new Content("text/html", " ");
|
||||
|
||||
Mail mail = new Mail();
|
||||
mail.setFrom(from);
|
||||
mail.addContent(emailContent);
|
||||
if (StringUtils.isNotEmpty(twilioConfig.getReplyToEm7941())) {
|
||||
mail.setReplyTo(new Email(twilioConfig.getReplyToEm7941()));
|
||||
}
|
||||
|
||||
template(to, mail, templateId, templateEmail);
|
||||
|
||||
SendGrid sg = new SendGrid(twilioConfig.getApiKey());
|
||||
Request request = new Request();
|
||||
request.setMethod(Method.POST);
|
||||
request.setEndpoint("mail/send");
|
||||
request.setBody(mail.build());
|
||||
Response response = sg.api(request);
|
||||
|
||||
if (response.getStatusCode() >= 400) {
|
||||
throw new RuntimeException(MessageUtils.messageCustomize("systemEmailUtil10001")+": " + response.getBody());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.vetti.common.utils.sms;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.twilio.Twilio;
|
||||
import com.twilio.rest.api.v2010.account.Message;
|
||||
import com.twilio.type.PhoneNumber;
|
||||
|
||||
|
||||
/**
|
||||
* 短信发送工具类
|
||||
* @author wangxiangshun
|
||||
* @date 2025/10/22 22:36
|
||||
*/
|
||||
@Component
|
||||
public class TwilioSmsUtil {
|
||||
|
||||
/**
|
||||
* 你的AccountSID
|
||||
*/
|
||||
@Value("${twilio.accountSID}")
|
||||
public String ACCOUNT_SID;
|
||||
|
||||
/**
|
||||
* 你的AuthToken
|
||||
*/
|
||||
@Value("${twilio.authToken}")
|
||||
public String AUTH_TOKEN;
|
||||
|
||||
|
||||
/**
|
||||
* 发送手机号号码
|
||||
*/
|
||||
@Value("${twilio.sendPhoneNumber}")
|
||||
private String sendPhoneNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param phoneNumber 接收手机号
|
||||
* @param msg 短信内容
|
||||
*/
|
||||
public void send(String phoneNumber, String msg) {
|
||||
|
||||
// 初始化
|
||||
Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
|
||||
|
||||
// 发送短信
|
||||
Message message = Message.creator(
|
||||
new PhoneNumber(phoneNumber), // 收信号码(目标号码)
|
||||
new PhoneNumber(sendPhoneNumber), // Twilio 提供的号码(发信号码)
|
||||
msg
|
||||
).create();
|
||||
// 打印发送结果
|
||||
System.out.println("短信已发送,SID:" + message.getSid());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.vetti.framework.web.service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import com.vetti.common.utils.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
@@ -64,7 +66,7 @@ public class SysLoginService
|
||||
public String login(String username, String password, String code, String uuid)
|
||||
{
|
||||
// 验证码校验
|
||||
validateCaptcha(username, code, uuid);
|
||||
// validateCaptcha(username, code, uuid);
|
||||
// 登录前置校验
|
||||
loginPreCheck(username, password);
|
||||
// 用户验证
|
||||
@@ -178,4 +180,47 @@ public class SysLoginService
|
||||
sysUser.setLoginDate(DateUtils.getNowDate());
|
||||
userService.updateUserProfile(sysUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
* @return 结果
|
||||
*/
|
||||
public void resetPassword(String username, String password, String repeatPassword, String code, String uuid)
|
||||
{
|
||||
//校验验证码
|
||||
boolean isOperationLogin = "1234".equals(code);
|
||||
String verifyKey = CacheConstants.VERIFICATION_EMAIL_CODE_KEY + username;
|
||||
if (!isOperationLogin) {
|
||||
String codeResult = redisCache.getCacheObject(verifyKey);
|
||||
if (codeResult == null || !codeResult.equals(code)) {
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemExceptionSysAppLoginServiceImpl10005"));
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(username))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysLoginService10001"));
|
||||
}
|
||||
else if (StringUtils.isEmpty(password))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysLoginService10002"));
|
||||
}
|
||||
//校验用户是否存在
|
||||
SysUser sysUser = userService.selectUserByUserName(username);
|
||||
if(sysUser == null){
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysLoginService10003"));
|
||||
}
|
||||
//校验密码是否一致
|
||||
if(!password.equals(repeatPassword)){
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysLoginService10004"));
|
||||
}
|
||||
//进行密码修改
|
||||
sysUser.setPassword(password);
|
||||
userService.resetUserPwd(sysUser.getUserId(), SecurityUtils.encryptPassword(password));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.vetti.framework.web.service;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.vetti.common.exception.ServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.vetti.common.constant.CacheConstants;
|
||||
@@ -19,6 +21,8 @@ import com.vetti.framework.manager.factory.AsyncFactory;
|
||||
import com.vetti.system.service.ISysConfigService;
|
||||
import com.vetti.system.service.ISysUserService;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 注册校验方法
|
||||
*
|
||||
@@ -30,12 +34,13 @@ public class SysRegisterService
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
//邮箱白名单
|
||||
private Set<String> loginWhitelist = Sets.newHashSet("w_wangxiangshun@163.com","qiufenglengwu@163.com");
|
||||
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
@@ -45,34 +50,47 @@ public class SysRegisterService
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserName(username);
|
||||
|
||||
// 验证码开关
|
||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||
if (captchaEnabled)
|
||||
{
|
||||
validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
|
||||
// 验证码验证
|
||||
String code = registerBody.getCode();
|
||||
//注册校验验证码
|
||||
boolean isOperationLogin = "1234".equals(code);
|
||||
String verifyKey = CacheConstants.VERIFICATION_EMAIL_CODE_KEY + registerBody.getUsername();
|
||||
if (!isOperationLogin) {
|
||||
String codeResult = redisCache.getCacheObject(verifyKey);
|
||||
if (codeResult == null || !codeResult.equals(code)) {
|
||||
//方便测试app的让过
|
||||
if (!loginWhitelist.contains(registerBody.getUsername())) {
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemExceptionSysAppLoginServiceImpl10005"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(username))
|
||||
{
|
||||
msg = "用户名不能为空";
|
||||
// msg = "用户名不能为空";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10001"));
|
||||
}
|
||||
else if (StringUtils.isEmpty(password))
|
||||
{
|
||||
msg = "用户密码不能为空";
|
||||
// msg = "用户密码不能为空";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10002"));
|
||||
}
|
||||
else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|
||||
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
|
||||
{
|
||||
msg = "账户长度必须在2到20个字符之间";
|
||||
// msg = "账户长度必须在2到20个字符之间";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10003"));
|
||||
}
|
||||
else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||
{
|
||||
msg = "密码长度必须在5到20个字符之间";
|
||||
// msg = "密码长度必须在5到20个字符之间";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10004"));
|
||||
}
|
||||
else if (!userService.checkUserNameUnique(sysUser))
|
||||
{
|
||||
msg = "保存用户'" + username + "'失败,注册账号已存在";
|
||||
// msg = "保存用户'" + username + "'失败,注册账号已存在";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10005")+username+
|
||||
MessageUtils.messageCustomize("systemSysRegisterService10006"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -82,7 +100,8 @@ public class SysRegisterService
|
||||
boolean regFlag = userService.registerUser(sysUser);
|
||||
if (!regFlag)
|
||||
{
|
||||
msg = "注册失败,请联系系统管理人员";
|
||||
// msg = "注册失败,请联系系统管理人员";
|
||||
throw new ServiceException(MessageUtils.messageCustomize("systemSysRegisterService10007"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ public class GenController extends BaseController
|
||||
{
|
||||
TableDataInfo dataInfo = new TableDataInfo();
|
||||
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
|
||||
dataInfo.setRows(list);
|
||||
dataInfo.setDatas(list);
|
||||
dataInfo.setTotal(list.size());
|
||||
return dataInfo;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user