feat(device): 实现设备与账号绑定管理机制
- 引入 ClientAccountDevice 表管理设备与账号绑定关系 - 重构设备注册逻辑,支持多账号绑定同一设备 - 新增设备配额检查,基于账号维度限制设备数量 -优化设备移除逻辑,仅解除绑定而非物理删除- 改进设备列表查询,通过账号ID关联获取设备信息 - 更新心跳任务,支持向设备绑定的所有账号发送心跳 - 调整设备API参数,增加username字段用于权限校验 -修复HTTP请求编码问题,统一使用UTF-8字符集 - 增强错误处理,携带错误码信息便于前端识别 - 移除设备表中的username字段,解耦设备与用户名关联
This commit is contained in:
@@ -31,6 +31,8 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import com.ruoyi.web.sse.SseHubService;
|
||||
import com.ruoyi.system.mapper.ClientDeviceMapper;
|
||||
import com.ruoyi.system.domain.ClientDevice;
|
||||
import com.ruoyi.system.mapper.ClientAccountDeviceMapper;
|
||||
import com.ruoyi.system.domain.ClientAccountDevice;
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,14 +58,18 @@ public class ClientAccountController extends BaseController {
|
||||
private SseHubService sseHubService;
|
||||
@Autowired
|
||||
private ClientDeviceMapper clientDeviceMapper;
|
||||
@Autowired
|
||||
private ClientAccountDeviceMapper accountDeviceMapper;
|
||||
|
||||
private AjaxResult checkDeviceLimit(String username, String deviceId, int deviceLimit) {
|
||||
List<ClientDevice> userDevices = clientDeviceMapper.selectByUsername(username);
|
||||
int userDevice = userDevices.size();
|
||||
boolean exists = userDevices.stream().anyMatch(d -> deviceId.equals(d.getDeviceId()));
|
||||
if (exists) userDevice--;
|
||||
if (userDevice >= deviceLimit) {
|
||||
return AjaxResult.error("设备数量已达上限(" + deviceLimit + "个),请先移除其他设备");
|
||||
private AjaxResult checkDeviceLimit(Long accountId, String deviceId, int deviceLimit) {
|
||||
int activeDeviceCount = accountDeviceMapper.countActiveDevicesByAccountId(accountId);
|
||||
ClientAccountDevice binding = accountDeviceMapper.selectByAccountIdAndDeviceId(accountId, deviceId);
|
||||
boolean exists = (binding != null && "active".equals(binding.getStatus()));
|
||||
if (exists) activeDeviceCount--;
|
||||
if (activeDeviceCount >= deviceLimit) {
|
||||
AjaxResult result = AjaxResult.error("设备数量已达上限(" + deviceLimit + "个),请先移除其他设备");
|
||||
result.put("code", 501);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -150,8 +156,10 @@ public class ClientAccountController extends BaseController {
|
||||
return AjaxResult.error("账号已被停用");
|
||||
}
|
||||
|
||||
AjaxResult limitCheck = checkDeviceLimit(username, clientId, account.getDeviceLimit());
|
||||
// 检查设备限制
|
||||
AjaxResult limitCheck = checkDeviceLimit(account.getId(), clientId, account.getDeviceLimit());
|
||||
if (limitCheck != null) return limitCheck;
|
||||
|
||||
String token = Jwts.builder()
|
||||
.setHeaderParam("kid", jwtRsaKeyService.getKeyId())
|
||||
.setSubject(username)
|
||||
@@ -163,25 +171,16 @@ public class ClientAccountController extends BaseController {
|
||||
.signWith(SignatureAlgorithm.RS256, jwtRsaKeyService.getPrivateKey())
|
||||
.compact();
|
||||
|
||||
boolean deviceTrialExpired = false;
|
||||
if ("trial".equals(account.getAccountType())) {
|
||||
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(clientId, username);
|
||||
deviceTrialExpired = device != null
|
||||
&& device.getTrialExpireTime() != null
|
||||
&& new Date().after(device.getTrialExpireTime());
|
||||
}
|
||||
|
||||
return AjaxResult.success(Map.of(
|
||||
"token", token,
|
||||
"permissions", account.getPermissions(),
|
||||
"accountName", account.getAccountName(),
|
||||
"expireTime", account.getExpireTime(),
|
||||
"accountType", account.getAccountType(),
|
||||
"deviceTrialExpired", deviceTrialExpired
|
||||
"accountType", account.getAccountType()
|
||||
));
|
||||
}
|
||||
/**
|
||||
* 验证token
|
||||
* 验证token
|
||||
*/
|
||||
@PostMapping("/verify")
|
||||
public AjaxResult verifyToken(@RequestBody Map<String, String> data) {
|
||||
@@ -204,9 +203,10 @@ public class ClientAccountController extends BaseController {
|
||||
clientAccountService.updateClientAccount(account);
|
||||
}
|
||||
|
||||
// 只有试用账号才检查设备试用期
|
||||
boolean deviceTrialExpired = false;
|
||||
if ("trial".equals(account.getAccountType())) {
|
||||
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(clientId, username);
|
||||
ClientDevice device = clientDeviceMapper.selectByDeviceId(clientId);
|
||||
deviceTrialExpired = device != null
|
||||
&& device.getTrialExpireTime() != null
|
||||
&& new Date().after(device.getTrialExpireTime());
|
||||
@@ -233,7 +233,6 @@ public class ClientAccountController extends BaseController {
|
||||
if (username == null || tokenClientId == null || !tokenClientId.equals(clientId)) {
|
||||
throw new RuntimeException("会话不匹配");
|
||||
}
|
||||
|
||||
SseEmitter emitter = sseHubService.register(username, clientId, 0L);
|
||||
try {
|
||||
emitter.send(SseEmitter.event().data("{\"type\":\"ready\"}"));
|
||||
@@ -260,6 +259,7 @@ public class ClientAccountController extends BaseController {
|
||||
clientAccount.setPermissions("{\"amazon\":true,\"rakuten\":true,\"zebra\":true}");
|
||||
clientAccount.setPassword(passwordEncoder.encode(password));
|
||||
clientAccount.setAccountType("trial");
|
||||
clientAccount.setDeviceLimit(3);
|
||||
clientAccount.setExpireTime(new Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||
|
||||
int result = clientAccountService.insertClientAccount(clientAccount);
|
||||
@@ -273,6 +273,7 @@ public class ClientAccountController extends BaseController {
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION))
|
||||
.claim("accountId", clientAccount.getId())
|
||||
.claim("username", username)
|
||||
.claim("clientId", deviceId)
|
||||
.signWith(SignatureAlgorithm.RS256, jwtRsaKeyService.getPrivateKey())
|
||||
.compact();
|
||||
@@ -282,8 +283,7 @@ public class ClientAccountController extends BaseController {
|
||||
"permissions", clientAccount.getPermissions(),
|
||||
"accountName", clientAccount.getAccountName(),
|
||||
"expireTime", clientAccount.getExpireTime(),
|
||||
"accountType", clientAccount.getAccountType(),
|
||||
"deviceTrialExpired", false
|
||||
"accountType", clientAccount.getAccountType()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,155 +6,124 @@ import com.ruoyi.system.mapper.ClientDeviceMapper;
|
||||
import com.ruoyi.system.mapper.ClientAccountMapper;
|
||||
import com.ruoyi.system.domain.ClientAccount;
|
||||
import com.ruoyi.web.sse.SseHubService;
|
||||
import com.ruoyi.system.mapper.ClientAccountDeviceMapper;
|
||||
import com.ruoyi.system.domain.ClientAccountDevice;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/monitor/device")
|
||||
@Anonymous
|
||||
public class ClientDeviceController {
|
||||
@Autowired
|
||||
private ClientDeviceMapper clientDeviceMapper;
|
||||
@Autowired
|
||||
private ClientAccountMapper clientAccountMapper;
|
||||
@Autowired
|
||||
private SseHubService sseHubService;
|
||||
private AjaxResult checkDeviceLimit(String username, String deviceId) {
|
||||
ClientAccount account = clientAccountMapper.selectClientAccountByUsername(username);
|
||||
int deviceLimit = (account != null && account.getDeviceLimit() != null) ? account.getDeviceLimit() : 3;
|
||||
List<ClientDevice> userDevices = clientDeviceMapper.selectByUsername(username);
|
||||
int userDevice = userDevices.size();
|
||||
boolean deviceExists = userDevices.stream().anyMatch(d -> deviceId.equals(d.getDeviceId()));
|
||||
if (deviceExists) userDevice--;
|
||||
if (userDevice >= deviceLimit) {
|
||||
return AjaxResult.error("设备数量已达上限(" + deviceLimit + "个),请先移除其他设备");
|
||||
}
|
||||
return null;
|
||||
@Autowired private ClientDeviceMapper deviceMapper;
|
||||
@Autowired private ClientAccountMapper accountMapper;
|
||||
@Autowired private ClientAccountDeviceMapper accountDeviceMapper;
|
||||
@Autowired private SseHubService sseHubService;
|
||||
|
||||
private ClientAccount getAccount(String username) {
|
||||
return accountMapper.selectClientAccountByUsername(username);
|
||||
}
|
||||
|
||||
private boolean exceedDeviceLimit(Long accountId, String deviceId, int limit) {
|
||||
int count = accountDeviceMapper.countActiveDevicesByAccountId(accountId);
|
||||
ClientAccountDevice binding = accountDeviceMapper.selectByAccountIdAndDeviceId(accountId, deviceId);
|
||||
if (binding != null && "active".equals(binding.getStatus())) count--;
|
||||
return count >= limit;
|
||||
}
|
||||
|
||||
@GetMapping("/quota")
|
||||
public AjaxResult quota(@RequestParam(value = "username", required = false) String username) {
|
||||
List<ClientDevice> all = clientDeviceMapper.selectByUsername(username);
|
||||
int used = 0;
|
||||
for (ClientDevice d : all) {
|
||||
if (!"removed".equals(d.getStatus())) used++;
|
||||
}
|
||||
ClientAccount account = clientAccountMapper.selectClientAccountByUsername(username);
|
||||
int limit = (account != null && account.getDeviceLimit() != null) ? account.getDeviceLimit() : 3;
|
||||
public AjaxResult quota(@RequestParam String username) {
|
||||
ClientAccount account = getAccount(username);
|
||||
int used = accountDeviceMapper.countActiveDevicesByAccountId(account.getId());
|
||||
int limit = account.getDeviceLimit() != null ? account.getDeviceLimit() : 3;
|
||||
return AjaxResult.success(Map.of("limit", limit, "used", used));
|
||||
}
|
||||
/**
|
||||
* 按用户名查询设备列表(最近活动优先)
|
||||
* @param username 用户名,必需参数
|
||||
* @return 设备列表
|
||||
*/
|
||||
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(@RequestParam("username") String username) {
|
||||
List<ClientDevice> list = clientDeviceMapper.selectByUsername(username);
|
||||
java.util.ArrayList<ClientDevice> active = new java.util.ArrayList<>();
|
||||
for (ClientDevice d : list) {
|
||||
if (!"removed".equals(d.getStatus())) active.add(d);
|
||||
}
|
||||
return AjaxResult.success(active);
|
||||
public AjaxResult list(@RequestParam String username) {
|
||||
return AjaxResult.success(accountDeviceMapper.selectDevicesByAccountId(getAccount(username).getId()));
|
||||
}
|
||||
/**
|
||||
* 设备注册
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody ClientDevice device, HttpServletRequest request) {
|
||||
String ip = device.getIp();
|
||||
String username = device.getUsername();
|
||||
String deviceId = device.getDeviceId();
|
||||
String os = device.getOs();
|
||||
String deviceName = username + "@" + ip + " (" + os + ")";
|
||||
|
||||
AjaxResult limitCheck = checkDeviceLimit(username, deviceId);
|
||||
if (limitCheck != null) return limitCheck;
|
||||
|
||||
ClientDevice exists = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||
if (exists == null) {
|
||||
|
||||
device.setIp(ip);
|
||||
device.setStatus("online");
|
||||
device.setLastActiveAt(new java.util.Date());
|
||||
device.setTrialExpireTime(new java.util.Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||
device.setName(deviceName);
|
||||
clientDeviceMapper.insert(device);
|
||||
} else {
|
||||
|
||||
exists.setName(deviceName);
|
||||
exists.setOs(os);
|
||||
exists.setStatus("online");
|
||||
exists.setIp(ip);
|
||||
exists.setLocation(device.getLocation());
|
||||
exists.setLastActiveAt(new java.util.Date());
|
||||
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||
public AjaxResult register(@RequestBody Map<String, String> data) {
|
||||
String username = data.get("username");
|
||||
String deviceId = data.get("deviceId");
|
||||
ClientAccount account = getAccount(username);
|
||||
int limit = account.getDeviceLimit() != null ? account.getDeviceLimit() : 3;
|
||||
|
||||
if (exceedDeviceLimit(account.getId(), deviceId, limit)) {
|
||||
return AjaxResult.error("设备数量已达上限(" + limit + "个)");
|
||||
}
|
||||
|
||||
ClientDevice device = deviceMapper.selectByDeviceId(deviceId);
|
||||
Date now = new Date();
|
||||
if (device == null) {
|
||||
device = new ClientDevice();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setName(username + "@" + data.get("ip") + " (" + data.get("os") + ")");
|
||||
device.setOs(data.get("os"));
|
||||
device.setIp(data.get("ip"));
|
||||
device.setLocation(data.get("location"));
|
||||
device.setTrialExpireTime(new Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||
deviceMapper.insert(device);
|
||||
}
|
||||
device.setStatus("online");
|
||||
device.setLastActiveAt(now);
|
||||
device.setIp(data.get("ip"));
|
||||
device.setLocation(data.get("location"));
|
||||
deviceMapper.updateByDeviceId(device);
|
||||
|
||||
ClientAccountDevice binding = accountDeviceMapper.selectByAccountIdAndDeviceId(account.getId(), deviceId);
|
||||
if (binding == null) {
|
||||
binding = new ClientAccountDevice();
|
||||
binding.setAccountId(account.getId());
|
||||
binding.setDeviceId(deviceId);
|
||||
binding.setBindTime(now);
|
||||
binding.setStatus("active");
|
||||
accountDeviceMapper.insert(binding);
|
||||
} else if ("removed".equals(binding.getStatus())) {
|
||||
accountDeviceMapper.updateStatus(account.getId(), deviceId, "active");
|
||||
}
|
||||
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名设备
|
||||
*
|
||||
* 根据 deviceId 更新 name。
|
||||
*/
|
||||
@PostMapping("/rename")
|
||||
public AjaxResult rename(@RequestBody ClientDevice device) {
|
||||
clientDeviceMapper.updateByDeviceId(device);
|
||||
deviceMapper.updateByDeviceId(device);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备试用期过期时间
|
||||
*/
|
||||
@PostMapping("/updateExpire")
|
||||
public AjaxResult updateExpire(@RequestBody ClientDevice device) {
|
||||
clientDeviceMapper.updateByDeviceIdAndUsername(device);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
/**
|
||||
* 移除设备
|
||||
* 根据 deviceId 删除设备绑定记录。
|
||||
*/
|
||||
@PostMapping("/remove")
|
||||
public AjaxResult remove(@RequestBody Map<String, String> body) {
|
||||
String deviceId = body.get("deviceId");
|
||||
String username = body.get("username");
|
||||
if (deviceId == null || deviceId.isEmpty()) {
|
||||
return AjaxResult.error("deviceId不能为空");
|
||||
}
|
||||
ClientDevice exists = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||
if (exists == null) {
|
||||
return AjaxResult.success();
|
||||
}
|
||||
if (!"removed".equals(exists.getStatus())) {
|
||||
exists.setStatus("removed");
|
||||
exists.setLastActiveAt(new java.util.Date());
|
||||
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||
sseHubService.sendEvent(username, deviceId, "DEVICE_REMOVED", "{}");
|
||||
sseHubService.disconnectDevice(username, deviceId);
|
||||
}
|
||||
deviceMapper.updateByDeviceId(device);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@PostMapping("/remove")
|
||||
public AjaxResult remove(@RequestBody Map<String, String> data) {
|
||||
String deviceId = data.get("deviceId");
|
||||
String username = data.get("username");
|
||||
Long accountId = getAccount(username).getId();
|
||||
|
||||
accountDeviceMapper.updateStatus(accountId, deviceId, "removed");
|
||||
sseHubService.sendEvent(username, deviceId, "DEVICE_REMOVED", "{}");
|
||||
sseHubService.disconnectDevice(username, deviceId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备离线
|
||||
*/
|
||||
@PostMapping("/offline")
|
||||
public AjaxResult offline(@RequestBody Map<String, String> body) {
|
||||
String deviceId = body.get("deviceId");
|
||||
String username = body.get("username");
|
||||
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||
public AjaxResult offline(@RequestBody Map<String, String> data) {
|
||||
ClientDevice device = deviceMapper.selectByDeviceId(data.get("deviceId"));
|
||||
if (device != null) {
|
||||
device.setStatus("offline");
|
||||
device.setLastActiveAt(new java.util.Date());
|
||||
clientDeviceMapper.updateByDeviceIdAndUsername(device);
|
||||
device.setLastActiveAt(new Date());
|
||||
deviceMapper.updateByDeviceId(device);
|
||||
}
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ruoyi.web.controller.tool;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -8,6 +9,9 @@ import com.ruoyi.common.annotation.Anonymous;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.domain.BanmaAccount;
|
||||
import com.ruoyi.system.domain.ClientAccount;
|
||||
import com.ruoyi.system.mapper.BanmaAccountMapper;
|
||||
import com.ruoyi.system.mapper.ClientAccountMapper;
|
||||
import com.ruoyi.system.service.IBanmaAccountService;
|
||||
|
||||
/**
|
||||
@@ -20,11 +24,32 @@ public class BanmaOrderController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IBanmaAccountService accountService;
|
||||
@Autowired
|
||||
private ClientAccountMapper clientAccountMapper;
|
||||
@Autowired
|
||||
private BanmaAccountMapper banmaAccountMapper;
|
||||
|
||||
@GetMapping("/accounts")
|
||||
public R<?> listAccounts(String name) {
|
||||
return R.ok(accountService.listSimple(name));
|
||||
}
|
||||
|
||||
@GetMapping("/account-limit")
|
||||
public R<?> getAccountLimit(String name) {
|
||||
int limit = 1;
|
||||
int count = 0;
|
||||
if (name != null) {
|
||||
ClientAccount client = clientAccountMapper.selectClientAccountByUsername(name);
|
||||
if (client != null && "paid".equals(client.getAccountType())
|
||||
&& client.getExpireTime() != null && new Date().before(client.getExpireTime())) {
|
||||
limit = 3;
|
||||
}
|
||||
BanmaAccount query = new BanmaAccount();
|
||||
query.setClientUsername(name);
|
||||
count = banmaAccountMapper.selectList(query).size();
|
||||
}
|
||||
return R.ok(Map.of("limit", limit, "count", count));
|
||||
}
|
||||
@PostMapping("/accounts")
|
||||
public R<?> saveAccount(@RequestBody BanmaAccount body, String name) {
|
||||
if (body.getId() == null && accountService.validateAndGetToken(body.getUsername(), body.getPassword()) == null) {
|
||||
|
||||
@@ -124,13 +124,6 @@ public class SseHubService {
|
||||
try {
|
||||
ClientDevice device = clientDeviceMapper.selectByDeviceId(deviceId);
|
||||
if (device != null) {
|
||||
if ("removed".equals(device.getStatus()) && "offline".equals(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("removed".equals(status)) {
|
||||
disconnectDevice(device.getUsername(), deviceId);
|
||||
}
|
||||
device.setStatus(status);
|
||||
device.setLastActiveAt(new Date());
|
||||
clientDeviceMapper.updateByDeviceId(device);
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.ruoyi.web.task;
|
||||
|
||||
import com.ruoyi.system.domain.ClientDevice;
|
||||
import com.ruoyi.system.mapper.ClientDeviceMapper;
|
||||
import com.ruoyi.system.mapper.ClientAccountDeviceMapper;
|
||||
import com.ruoyi.system.mapper.ClientAccountMapper;
|
||||
import com.ruoyi.system.domain.ClientAccount;
|
||||
import com.ruoyi.web.sse.SseHubService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -20,6 +23,12 @@ public class DeviceHeartbeatTask {
|
||||
@Autowired
|
||||
private ClientDeviceMapper clientDeviceMapper;
|
||||
|
||||
@Autowired
|
||||
private ClientAccountDeviceMapper accountDeviceMapper;
|
||||
|
||||
@Autowired
|
||||
private ClientAccountMapper accountMapper;
|
||||
|
||||
@Autowired
|
||||
private SseHubService sseHubService;
|
||||
|
||||
@@ -30,7 +39,15 @@ public class DeviceHeartbeatTask {
|
||||
public void sendHeartbeatPing() {
|
||||
List<ClientDevice> onlineDevices = clientDeviceMapper.selectOnlineDevices();
|
||||
for (ClientDevice device : onlineDevices) {
|
||||
sseHubService.sendPing(device.getUsername(), device.getDeviceId());
|
||||
String deviceId = device.getDeviceId();
|
||||
// 查询该设备绑定的所有账号
|
||||
List<Long> accountIds = accountDeviceMapper.selectAccountIdsByDeviceId(deviceId);
|
||||
for (Long accountId : accountIds) {
|
||||
ClientAccount account = accountMapper.selectClientAccountById(accountId);
|
||||
if (account != null) {
|
||||
sseHubService.sendPing(account.getUsername(), deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,8 +62,15 @@ spring:
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
encoding: UTF-8
|
||||
profiles:
|
||||
active: druid
|
||||
# HTTP编码
|
||||
http:
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
enabled: true
|
||||
force: true
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
|
||||
Reference in New Issue
Block a user