Merge pull request '单点登录功能、任务日志问题修复、抽数服务放入基础模块等' (#6) from xinwei into master
Reviewed-on: http://120.46.37.243:3000/lundu/ludu-cloud/pulls/6
This commit is contained in:
commit
3f7e9f1062
@ -7,13 +7,13 @@ import com.xxl.job.admin.api.log.dto.JobLogPageReqDTO;
|
|||||||
import com.xxl.job.admin.api.log.dto.JobLogRespDTO;
|
import com.xxl.job.admin.api.log.dto.JobLogRespDTO;
|
||||||
import com.xxl.job.admin.enums.ApiConstants;
|
import com.xxl.job.admin.enums.ApiConstants;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description 调度任务日志Api接口
|
* @Description 调度任务日志Api接口
|
||||||
@ -24,5 +24,15 @@ public interface JobLogApi {
|
|||||||
String PREFIX = ApiConstants.PREFIX + "/log";
|
String PREFIX = ApiConstants.PREFIX + "/log";
|
||||||
@GetMapping(PREFIX + "/page")
|
@GetMapping(PREFIX + "/page")
|
||||||
@Operation(summary = "获得所有任务列表")
|
@Operation(summary = "获得所有任务列表")
|
||||||
public CommonResult<PageResult<JobLogRespDTO>> getPage(@Valid JobLogPageReqDTO jobLogPageReqDTO);
|
public CommonResult<PageResult<JobLogRespDTO>> getPage(@RequestParam(value = "pageNo") Integer pageNo,
|
||||||
|
@RequestParam(value = "pageSize") Integer pageSize,
|
||||||
|
@RequestParam(value = "jobId") Integer jobId,
|
||||||
|
@RequestParam(required = false, value = "handlerName") String handlerName,
|
||||||
|
@RequestParam(required = false, value = "beginTime") String beginTime,
|
||||||
|
@RequestParam(required = false, value = "endTime") String endTime,
|
||||||
|
@RequestParam(required = false, value = "status") Integer status);
|
||||||
|
|
||||||
|
@GetMapping(PREFIX + "/get")
|
||||||
|
@Operation(summary = "获得任务日志详情")
|
||||||
|
CommonResult<JobLogRespDTO> get(@RequestParam("id") Integer id);
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,9 @@ public class JobLogPageReqDTO extends PageParam {
|
|||||||
@Schema(description = "处理器的名字")
|
@Schema(description = "处理器的名字")
|
||||||
private String handlerName;
|
private String handlerName;
|
||||||
@Schema(description = "开始执行时间")
|
@Schema(description = "开始执行时间")
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
private String beginTime;
|
||||||
private Date beginTime;
|
|
||||||
@Schema(description = "结束执行时间")
|
@Schema(description = "结束执行时间")
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
private String endTime;
|
||||||
private Date endTime;
|
|
||||||
@Schema(description = "任务状态")
|
@Schema(description = "任务状态")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,16 @@ public class JobLogRespDTO {
|
|||||||
private Integer executeIndex;
|
private Integer executeIndex;
|
||||||
@Schema(description = "开始执行时间")
|
@Schema(description = "开始执行时间")
|
||||||
@ExcelProperty("开始执行时间")
|
@ExcelProperty("开始执行时间")
|
||||||
private Date beginTime;
|
private String beginTime;
|
||||||
@Schema(description = "结束执行时间")
|
@Schema(description = "结束执行时间")
|
||||||
@ExcelProperty("结束执行时间")
|
@ExcelProperty("结束执行时间")
|
||||||
private Date endTime;
|
private String endTime;
|
||||||
@Schema(description = "执行时长")
|
@Schema(description = "执行时长")
|
||||||
@ExcelProperty("执行时长")
|
@ExcelProperty("执行时长")
|
||||||
private Integer duration;
|
private Integer duration;
|
||||||
@Schema(description = "任务状态")
|
@Schema(description = "任务状态")
|
||||||
@ExcelProperty("任务状态")
|
@ExcelProperty("任务状态")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
@Schema(description = "任务详细结果")
|
||||||
|
private String result;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>xxl-job-admin</artifactId>
|
<artifactId>xxl-job-admin</artifactId>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
<version>2.1.0-jdk8-snapshot</version>
|
<version>${revision}</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -23,8 +23,28 @@
|
|||||||
<artifactId>ludu-job-core</artifactId>
|
<artifactId>ludu-job-core</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
|
<artifactId>yudao-module-system</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
<!-- Spring Cloud 基础 -->
|
<!-- Spring Cloud 基础 -->
|
||||||
|
<!-- Web 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.8.22</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
<artifactId>ludu-job-admin-api</artifactId>
|
<artifactId>ludu-job-admin-api</artifactId>
|
||||||
@ -62,10 +82,6 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
<!-- Web 相关 -->
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-security</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -9,14 +9,23 @@ import com.xxl.job.admin.api.log.dto.JobLogRespDTO;
|
|||||||
import com.xxl.job.admin.controller.JobInfoController;
|
import com.xxl.job.admin.controller.JobInfoController;
|
||||||
import com.xxl.job.admin.controller.JobLogController;
|
import com.xxl.job.admin.controller.JobLogController;
|
||||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||||
|
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||||
|
import com.xxl.job.admin.core.util.I18nUtil;
|
||||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||||
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
||||||
import com.xxl.job.admin.dao.XxlJobLogDao;
|
import com.xxl.job.admin.dao.XxlJobLogDao;
|
||||||
|
import com.xxl.job.core.biz.ExecutorBiz;
|
||||||
|
import com.xxl.job.core.biz.model.LogParam;
|
||||||
|
import com.xxl.job.core.biz.model.LogResult;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
import com.xxl.job.core.util.DateUtil;
|
import com.xxl.job.core.util.DateUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.util.HtmlUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -40,17 +49,71 @@ public class JobLogApiImpl implements JobLogApi {
|
|||||||
public XxlJobLogDao xxlJobLogDao;
|
public XxlJobLogDao xxlJobLogDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<PageResult<JobLogRespDTO>> getPage(JobLogPageReqDTO jobLogPageReqDTO) {
|
public CommonResult<PageResult<JobLogRespDTO>> getPage(Integer pageNo,
|
||||||
|
Integer pageSize,
|
||||||
|
Integer jobId,
|
||||||
|
String handlerName,
|
||||||
|
String beginTime,
|
||||||
|
String endTime,
|
||||||
|
Integer status) {
|
||||||
// 设置默认组为3
|
// 设置默认组为3
|
||||||
int jobGroup = 3;
|
int jobGroup = 3;
|
||||||
int status = jobLogPageReqDTO.getStatus() == null ? -1 : jobLogPageReqDTO.getStatus();
|
// 计算起始页数
|
||||||
|
pageNo = (pageNo - 1) * pageSize;
|
||||||
// page query
|
// page query
|
||||||
List<JobLogRespDTO> list = xxlJobLogDao.apiPageList(jobLogPageReqDTO.getPageNo(), jobLogPageReqDTO.getPageSize(), jobGroup, jobLogPageReqDTO.getJobId(), jobLogPageReqDTO.getBeginTime(), jobLogPageReqDTO.getEndTime(), status);
|
List<JobLogRespDTO> list = xxlJobLogDao.apiPageList(pageNo, pageSize, jobGroup, jobId, beginTime, endTime, status, handlerName);
|
||||||
int list_count = xxlJobLogDao.pageListCount(jobLogPageReqDTO.getPageNo(), jobLogPageReqDTO.getPageSize(), jobGroup, jobLogPageReqDTO.getJobId(), jobLogPageReqDTO.getBeginTime(), jobLogPageReqDTO.getEndTime(), status);
|
int list_count = xxlJobLogDao.apiPageListCount(pageNo, pageSize, jobGroup, jobId, beginTime, endTime, status, handlerName);
|
||||||
// package result
|
// package result
|
||||||
PageResult<JobLogRespDTO> pageResult = new PageResult<>();
|
PageResult<JobLogRespDTO> pageResult = new PageResult<>();
|
||||||
pageResult.setTotal((long) list_count);
|
pageResult.setTotal((long) list_count);
|
||||||
pageResult.setList(list);
|
pageResult.setList(list);
|
||||||
return CommonResult.success(pageResult);
|
return CommonResult.success(pageResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<JobLogRespDTO> get(Integer id) {
|
||||||
|
XxlJobLog load = xxlJobLogDao.load(id);
|
||||||
|
JobLogRespDTO jobLogRespDTO = new JobLogRespDTO();
|
||||||
|
jobLogRespDTO.setId(id);
|
||||||
|
jobLogRespDTO.setJobId(load.getJobId());
|
||||||
|
if (load.getTriggerCode() == 200) {
|
||||||
|
jobLogRespDTO.setDuration((int) (load.getHandleTime().getTime() - load.getTriggerTime().getTime()));
|
||||||
|
}
|
||||||
|
jobLogRespDTO.setBeginTime(load.getTriggerTime() == null ? null : DateUtil.formatDateTime(load.getTriggerTime()));
|
||||||
|
jobLogRespDTO.setEndTime(load.getHandleTime() == null ? null : DateUtil.formatDateTime(load.getHandleTime()));
|
||||||
|
jobLogRespDTO.setHandlerName(load.getExecutorHandler());
|
||||||
|
jobLogRespDTO.setHandlerParam(load.getExecutorParam());
|
||||||
|
jobLogRespDTO.setStatus(load.getHandleCode() == 200 ? 1 : 2);
|
||||||
|
// 使用原系统的方法实现日志结果显示
|
||||||
|
try {
|
||||||
|
// valid
|
||||||
|
XxlJobLog jobLog = xxlJobLogDao.load(id);
|
||||||
|
if (jobLog == null) {
|
||||||
|
jobLogRespDTO.setResult("joblog_logid_unvalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// log cat
|
||||||
|
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
|
||||||
|
ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), id, 1));
|
||||||
|
|
||||||
|
// is end
|
||||||
|
if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
|
||||||
|
if (jobLog.getHandleCode() > 0) {
|
||||||
|
logResult.getContent().setEnd(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix xss
|
||||||
|
if (logResult.getContent() != null && StringUtils.hasText(logResult.getContent().getLogContent())) {
|
||||||
|
String newLogContent = logResult.getContent().getLogContent();
|
||||||
|
newLogContent = HtmlUtils.htmlEscape(newLogContent, "UTF-8");
|
||||||
|
logResult.getContent().setLogContent(newLogContent);
|
||||||
|
}
|
||||||
|
jobLogRespDTO.setResult(logResult.getContent().getLogContent());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
jobLogRespDTO.setResult("joblog_logid_failed");
|
||||||
|
}
|
||||||
|
return CommonResult.success(jobLogRespDTO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
package com.xxl.job.admin.client;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.Base64Utils;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth 2.0 客户端
|
||||||
|
*
|
||||||
|
* 对应调用 OAuth2OpenController 接口
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class OAuth2Client {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户编号
|
||||||
|
*
|
||||||
|
* 默认使用 1;如果使用别的租户,可以调整
|
||||||
|
*/
|
||||||
|
public static final Long TENANT_ID = 1L;
|
||||||
|
|
||||||
|
private static final String CLIENT_ID = "ludu-job-admin";
|
||||||
|
private static final String CLIENT_SECRET = "test";
|
||||||
|
|
||||||
|
|
||||||
|
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||||
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 code 授权码,获得访问令牌
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @param redirectUri 重定向 URI
|
||||||
|
* @return 访问令牌
|
||||||
|
*/
|
||||||
|
public CommonResult<OAuth2AccessTokenRespDTO> postAccessToken(String code, String redirectUri) {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", TENANT_ID.toString());
|
||||||
|
addClientHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("grant_type", "authorization_code");
|
||||||
|
body.add("code", code);
|
||||||
|
body.add("redirect_uri", redirectUri);
|
||||||
|
// body.add("state", ""); // 选填;填了会校验
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/token",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验访问令牌,并返回它的基本信息
|
||||||
|
*
|
||||||
|
* @param token 访问令牌
|
||||||
|
* @return 访问令牌的基本信息
|
||||||
|
*/
|
||||||
|
public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", TENANT_ID.toString());
|
||||||
|
addClientHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("token", token);
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<OAuth2CheckTokenRespDTO>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/check-token",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<OAuth2CheckTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用刷新令牌,获得(刷新)访问令牌
|
||||||
|
*
|
||||||
|
* @param refreshToken 刷新令牌
|
||||||
|
* @return 访问令牌
|
||||||
|
*/
|
||||||
|
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(String refreshToken) {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", TENANT_ID.toString());
|
||||||
|
addClientHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("grant_type", "refresh_token");
|
||||||
|
body.add("refresh_token", refreshToken);
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/token",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除访问令牌
|
||||||
|
*
|
||||||
|
* @param token 访问令牌
|
||||||
|
* @return 成功
|
||||||
|
*/
|
||||||
|
public CommonResult<Boolean> revokeToken(String token) {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", TENANT_ID.toString());
|
||||||
|
addClientHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("token", token);
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/token",
|
||||||
|
HttpMethod.DELETE,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addClientHeader(HttpHeaders headers) {
|
||||||
|
// client 拼接,需要 BASE64 编码
|
||||||
|
String client = CLIENT_ID + ":" + CLIENT_SECRET;
|
||||||
|
client = Base64Utils.encodeToString(client.getBytes(StandardCharsets.UTF_8));
|
||||||
|
headers.add("Authorization", "Basic " + client);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.xxl.job.admin.client;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.client.dto.user.UserInfoRespDTO;
|
||||||
|
import com.xxl.job.admin.client.dto.user.UserUpdateReqDTO;
|
||||||
|
import com.xxl.job.admin.framework.security.core.LoginUser;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.SecurityUtils;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户 User 信息的客户端
|
||||||
|
*
|
||||||
|
* 对应调用 OAuth2UserController 接口
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UserClient {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2/user";
|
||||||
|
|
||||||
|
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||||
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
public CommonResult<UserInfoRespDTO> getUser() {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||||
|
addTokenHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<UserInfoRespDTO>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/get",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<UserInfoRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommonResult<Boolean> updateUser(UserUpdateReqDTO updateReqDTO) {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||||
|
addTokenHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
// 使用 updateReqDTO 即可
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/update",
|
||||||
|
HttpMethod.PUT,
|
||||||
|
new HttpEntity<>(updateReqDTO, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void addTokenHeader(HttpHeaders headers) {
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
Assert.notNull(loginUser, "登录用户不能为空");
|
||||||
|
headers.add("Authorization", "Bearer " + loginUser.getAccessToken());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.xxl.job.admin.client.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用返回
|
||||||
|
*
|
||||||
|
* @param <T> 数据泛型
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommonResult<T> implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
/**
|
||||||
|
* 返回数据
|
||||||
|
*/
|
||||||
|
private T data;
|
||||||
|
/**
|
||||||
|
* 错误提示,用户可阅读
|
||||||
|
*/
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.xxl.job.admin.client.dto.oauth2;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌 Response DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OAuth2AccessTokenRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌
|
||||||
|
*/
|
||||||
|
@JsonProperty("access_token")
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新令牌
|
||||||
|
*/
|
||||||
|
@JsonProperty("refresh_token")
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌类型
|
||||||
|
*/
|
||||||
|
@JsonProperty("token_type")
|
||||||
|
private String tokenType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间;单位:秒
|
||||||
|
*/
|
||||||
|
@JsonProperty("expires_in")
|
||||||
|
private Long expiresIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权范围;如果多个授权范围,使用空格分隔
|
||||||
|
*/
|
||||||
|
private String scope;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.xxl.job.admin.client.dto.oauth2;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验令牌 Response DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OAuth2CheckTokenRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
@JsonProperty("user_id")
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
@JsonProperty("user_type")
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 租户编号
|
||||||
|
*/
|
||||||
|
@JsonProperty("tenant_id")
|
||||||
|
private Long tenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端编号
|
||||||
|
*/
|
||||||
|
@JsonProperty("client_id")
|
||||||
|
private String clientId;
|
||||||
|
/**
|
||||||
|
* 授权范围
|
||||||
|
*/
|
||||||
|
private List<String> scopes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌
|
||||||
|
*/
|
||||||
|
@JsonProperty("access_token")
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间
|
||||||
|
*
|
||||||
|
* 时间戳 / 1000,即单位:秒
|
||||||
|
*/
|
||||||
|
private Long exp;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package com.xxl.job.admin.client.dto.user;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得用户基本信息 Response dto
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserInfoRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户邮箱
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* 手机号码
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户性别
|
||||||
|
*/
|
||||||
|
private Integer sex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所在部门
|
||||||
|
*/
|
||||||
|
private Dept dept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属岗位数组
|
||||||
|
*/
|
||||||
|
private List<Post> posts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Dept {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Post {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.xxl.job.admin.client.dto.user;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户基本信息 Request DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserUpdateReqDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户邮箱
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号码
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户性别
|
||||||
|
*/
|
||||||
|
private Integer sex;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.xxl.job.admin.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.xxl.job.admin.client.OAuth2Client;
|
||||||
|
import com.xxl.job.admin.client.UserClient;
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||||
|
import com.xxl.job.admin.client.dto.user.UserInfoRespDTO;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.SecurityUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/auth")
|
||||||
|
public class AuthController {
|
||||||
|
@Resource
|
||||||
|
private UserClient userClient;
|
||||||
|
@Resource
|
||||||
|
private OAuth2Client oauth2Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 code 访问令牌,获得访问令牌
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @param redirectUri 重定向 URI
|
||||||
|
* @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||||
|
*/
|
||||||
|
@PostMapping("/login-by-code")
|
||||||
|
public CommonResult<OAuth2AccessTokenRespDTO> loginByCode(@RequestParam("code") String code,
|
||||||
|
@RequestParam("redirectUri") String redirectUri) {
|
||||||
|
return oauth2Client.postAccessToken(code, redirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用刷新令牌,获得(刷新)访问令牌
|
||||||
|
*
|
||||||
|
* @param refreshToken 刷新令牌
|
||||||
|
* @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||||
|
*/
|
||||||
|
@PostMapping("/refresh-token")
|
||||||
|
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||||
|
return oauth2Client.refreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出登录
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @return 成功
|
||||||
|
*/
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||||
|
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||||
|
if (StrUtil.isNotBlank(token)) {
|
||||||
|
return oauth2Client.revokeToken(token);
|
||||||
|
}
|
||||||
|
// 返回成功
|
||||||
|
return new CommonResult<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前登录用户的基本信息
|
||||||
|
*
|
||||||
|
* @return 用户信息;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||||
|
*/
|
||||||
|
@GetMapping("/get")
|
||||||
|
public CommonResult<UserInfoRespDTO> getUser() {
|
||||||
|
return userClient.getUser();
|
||||||
|
}
|
||||||
|
}
|
@ -54,10 +54,10 @@ public class IndexController {
|
|||||||
@RequestMapping("/toLogin")
|
@RequestMapping("/toLogin")
|
||||||
@PermissionLimit(limit=false)
|
@PermissionLimit(limit=false)
|
||||||
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response,ModelAndView modelAndView) {
|
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response,ModelAndView modelAndView) {
|
||||||
if (loginService.ifLogin(request, response) != null) {
|
/*if (loginService.ifLogin(request, response) != null) {
|
||||||
modelAndView.setView(new RedirectView("/",true,false));
|
modelAndView.setView(new RedirectView("/",true,false));
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}*/
|
||||||
return new ModelAndView("login");
|
return new ModelAndView("login");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,8 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
|
|||||||
|
|
||||||
if (needLogin) {
|
if (needLogin) {
|
||||||
XxlJobUser loginUser = loginService.ifLogin(request, response);
|
XxlJobUser loginUser = loginService.ifLogin(request, response);
|
||||||
if (loginUser == null) {
|
Boolean authorState = loginService.ifAuthorizedLogin(request, response);
|
||||||
|
if (loginUser == null || !authorState) {
|
||||||
response.setStatus(302);
|
response.setStatus(302);
|
||||||
response.setHeader("location", request.getContextPath()+"/toLogin");
|
response.setHeader("location", request.getContextPath()+"/toLogin");
|
||||||
return false;
|
return false;
|
||||||
@ -53,7 +54,6 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
|
|||||||
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
|
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 未解决单点登录问题 暂时直接放行 前面有网关的系统登录拦截
|
|
||||||
return true; // proceed with the next interceptor
|
return true; // proceed with the next interceptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.xxl.job.admin.controller.interceptor;
|
package com.xxl.job.admin.controller.interceptor;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.enums.ApiConstants;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
@ -21,8 +22,8 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
|
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**");
|
||||||
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
|
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -37,7 +37,7 @@ public class CookieUtil {
|
|||||||
* @param value
|
* @param value
|
||||||
* @param maxAge
|
* @param maxAge
|
||||||
*/
|
*/
|
||||||
private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
|
public static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
|
||||||
Cookie cookie = new Cookie(key, value);
|
Cookie cookie = new Cookie(key, value);
|
||||||
if (domain != null) {
|
if (domain != null) {
|
||||||
cookie.setDomain(domain);
|
cookie.setDomain(domain);
|
||||||
@ -89,10 +89,20 @@ public class CookieUtil {
|
|||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
|
public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
|
||||||
Cookie cookie = get(request, key);
|
remove(request, response, key, COOKIE_PATH);
|
||||||
if (cookie != null) {
|
|
||||||
set(response, key, "", null, COOKIE_PATH, 0, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Cookie(自定义作用范围路径)
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
public static void remove(HttpServletRequest request, HttpServletResponse response, String key, String path) {
|
||||||
|
Cookie cookie = get(request, key);
|
||||||
|
if (cookie != null) {
|
||||||
|
set(response, key, "", null, path, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -28,9 +28,10 @@ public interface XxlJobLogDao {
|
|||||||
@Param("pagesize") int pagesize,
|
@Param("pagesize") int pagesize,
|
||||||
@Param("jobGroup") int jobGroup,
|
@Param("jobGroup") int jobGroup,
|
||||||
@Param("jobId") int jobId,
|
@Param("jobId") int jobId,
|
||||||
@Param("triggerTimeStart") Date triggerTimeStart,
|
@Param("triggerTimeStart") String triggerTimeStart,
|
||||||
@Param("triggerTimeEnd") Date triggerTimeEnd,
|
@Param("triggerTimeEnd") String triggerTimeEnd,
|
||||||
@Param("logStatus") Integer logStatus);
|
@Param("logStatus") Integer logStatus,
|
||||||
|
@Param("handlerName") String handlerName);
|
||||||
public int pageListCount(@Param("offset") int offset,
|
public int pageListCount(@Param("offset") int offset,
|
||||||
@Param("pagesize") int pagesize,
|
@Param("pagesize") int pagesize,
|
||||||
@Param("jobGroup") int jobGroup,
|
@Param("jobGroup") int jobGroup,
|
||||||
@ -67,4 +68,12 @@ public interface XxlJobLogDao {
|
|||||||
|
|
||||||
public List<Long> findLostJobIds(@Param("losedTime") Date losedTime);
|
public List<Long> findLostJobIds(@Param("losedTime") Date losedTime);
|
||||||
|
|
||||||
|
int apiPageListCount(@Param("offset") int offset,
|
||||||
|
@Param("pagesize") int pagesize,
|
||||||
|
@Param("jobGroup") int jobGroup,
|
||||||
|
@Param("jobId") int jobId,
|
||||||
|
@Param("triggerTimeStart") String triggerTimeStart,
|
||||||
|
@Param("triggerTimeEnd") String triggerTimeEnd,
|
||||||
|
@Param("logStatus") Integer logStatus,
|
||||||
|
@Param("handlerName") String handlerName);
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,58 @@
|
|||||||
package com.xxl.job.admin.framework.security.config;
|
package com.xxl.job.admin.framework.security.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
|
|
||||||
import com.xxl.job.admin.enums.ApiConstants;
|
import com.xxl.job.admin.enums.ApiConstants;
|
||||||
|
import com.xxl.job.admin.framework.security.core.filter.TokenAuthenticationFilter;
|
||||||
|
import com.xxl.job.admin.framework.security.core.handler.AccessDeniedHandlerImpl;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Demo 模块的 Security 配置
|
* Demo 模块的 Security 配置
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableWebSecurity
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
@Resource
|
||||||
|
private TokenAuthenticationFilter tokenAuthenticationFilter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AccessDeniedHandlerImpl accessDeniedHandler;
|
||||||
|
@Resource
|
||||||
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||||
return new AuthorizeRequestsCustomizer() {
|
// 设置 URL 安全权限
|
||||||
|
httpSecurity.csrf().disable() // 禁用 CSRF 保护
|
||||||
|
.authorizeRequests()
|
||||||
|
// 1. 静态资源,可匿名访问
|
||||||
|
.antMatchers("/**").permitAll()
|
||||||
|
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||||
|
// 2. 登录相关的接口,可匿名访问
|
||||||
|
.antMatchers("/toLogin").permitAll()
|
||||||
|
.antMatchers("/auth/login-by-code").permitAll()
|
||||||
|
.antMatchers("/auth/refresh-token").permitAll()
|
||||||
|
.antMatchers("/auth/logout").permitAll()
|
||||||
|
// last. 兜底规则,必须认证
|
||||||
|
.and().authorizeRequests()
|
||||||
|
.anyRequest().authenticated();
|
||||||
|
|
||||||
@Override
|
// 设置处理器
|
||||||
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
|
httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
|
||||||
// Swagger 接口文档
|
.authenticationEntryPoint(authenticationEntryPoint);
|
||||||
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
|
|
||||||
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
|
|
||||||
// Druid 监控
|
|
||||||
registry.antMatchers("/druid/**").anonymous();
|
|
||||||
// Spring Boot Actuator 的安全配置
|
|
||||||
registry.antMatchers("/actuator").anonymous()
|
|
||||||
.antMatchers("/actuator/**").anonymous();
|
|
||||||
// RPC 服务的安全配置
|
|
||||||
registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
|
||||||
// 放行所有后台原本请求和rpc接口
|
|
||||||
registry.antMatchers("/**").permitAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
// 添加 Token Filter
|
||||||
|
httpSecurity.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
return httpSecurity.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录用户信息
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LoginUser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 租户编号
|
||||||
|
*/
|
||||||
|
private Long tenantId;
|
||||||
|
/**
|
||||||
|
* 授权范围
|
||||||
|
*/
|
||||||
|
private List<String> scopes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core.filter;
|
||||||
|
|
||||||
|
|
||||||
|
import com.xxl.job.admin.client.OAuth2Client;
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||||
|
import com.xxl.job.admin.framework.security.core.LoginUser;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.SecurityUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token 过滤器,验证 token 的有效性
|
||||||
|
* 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OAuth2Client oauth2Client;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
// 1. 获得访问令牌
|
||||||
|
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||||
|
if (StringUtils.hasText(token)) {
|
||||||
|
// 2. 基于 token 构建登录用户
|
||||||
|
LoginUser loginUser = buildLoginUserByToken(token);
|
||||||
|
// 3. 设置当前用户
|
||||||
|
if (loginUser != null) {
|
||||||
|
SecurityUtils.setLoginUser(loginUser, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续过滤链
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginUser buildLoginUserByToken(String token) {
|
||||||
|
try {
|
||||||
|
CommonResult<OAuth2CheckTokenRespDTO> accessTokenResult = oauth2Client.checkToken(token);
|
||||||
|
OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData();
|
||||||
|
if (accessToken == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 构建登录用户
|
||||||
|
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||||
|
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
|
||||||
|
.setAccessToken(accessToken.getAccessToken());
|
||||||
|
} catch (Exception exception) {
|
||||||
|
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core.handler;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.SecurityUtils;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.ServletUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。
|
||||||
|
*
|
||||||
|
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#handleAccessDeniedException(HttpServletRequest, HttpServletResponse, FilterChain, AccessDeniedException)} 方法,调用当前类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@SuppressWarnings("JavadocReference")
|
||||||
|
@Slf4j
|
||||||
|
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
// 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏
|
||||||
|
log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(),
|
||||||
|
SecurityUtils.getLoginUserId(), e);
|
||||||
|
// 返回 403
|
||||||
|
CommonResult<Object> result = new CommonResult<>();
|
||||||
|
result.setCode(HttpStatus.FORBIDDEN.value());
|
||||||
|
result.setMsg("没有该操作权限");
|
||||||
|
ServletUtils.writeJSON(response, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core.handler;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.ServletUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页
|
||||||
|
*
|
||||||
|
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@SuppressWarnings("JavadocReference") // 忽略文档引用报错
|
||||||
|
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
|
||||||
|
log.debug("[commence][访问 URL({}) 时,没有登录]", request.getRequestURI(), e);
|
||||||
|
// 返回 401
|
||||||
|
CommonResult<Object> result = new CommonResult<>();
|
||||||
|
result.setCode(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
result.setMsg("账号未登录");
|
||||||
|
ServletUtils.writeJSON(response, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core.util;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.framework.security.core.LoginUser;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全服务工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class SecurityUtils {
|
||||||
|
|
||||||
|
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||||
|
|
||||||
|
private SecurityUtils() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从请求中,获得认证 Token
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param header 认证 Token 对应的 Header 名字
|
||||||
|
* @return 认证 Token
|
||||||
|
*/
|
||||||
|
public static String obtainAuthorization(HttpServletRequest request, String header) {
|
||||||
|
String authorization = request.getHeader(header);
|
||||||
|
if (!StringUtils.hasText(authorization)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
||||||
|
if (index == -1) { // 未找到
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return authorization.substring(index + 7).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前认证信息
|
||||||
|
*
|
||||||
|
* @return 认证信息
|
||||||
|
*/
|
||||||
|
public static Authentication getAuthentication() {
|
||||||
|
SecurityContext context = SecurityContextHolder.getContext();
|
||||||
|
if (context == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return context.getAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户
|
||||||
|
*
|
||||||
|
* @return 当前用户
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static LoginUser getLoginUser() {
|
||||||
|
Authentication authentication = getAuthentication();
|
||||||
|
if (authentication == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前用户的编号,从上下文中
|
||||||
|
*
|
||||||
|
* @return 用户编号
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Long getLoginUserId() {
|
||||||
|
LoginUser loginUser = getLoginUser();
|
||||||
|
return loginUser != null ? loginUser.getId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前用户
|
||||||
|
*
|
||||||
|
* @param loginUser 登录用户
|
||||||
|
* @param request 请求
|
||||||
|
*/
|
||||||
|
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
||||||
|
// 创建 Authentication,并设置到上下文
|
||||||
|
Authentication authentication = buildAuthentication(loginUser, request);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
||||||
|
// 创建 UsernamePasswordAuthenticationToken 对象
|
||||||
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
loginUser, null, Collections.emptyList());
|
||||||
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
return authenticationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.xxl.job.admin.framework.security.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class ServletUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回 JSON 字符串
|
||||||
|
*
|
||||||
|
* @param response 响应
|
||||||
|
* @param object 对象,会序列化成 JSON 字符串
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
|
||||||
|
public static void writeJSON(HttpServletResponse response, Object object) {
|
||||||
|
String content = JSONUtil.toJsonStr(object);
|
||||||
|
ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void write(HttpServletResponse response, String text, String contentType) {
|
||||||
|
ServletUtil.write(response, text, contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,23 @@
|
|||||||
package com.xxl.job.admin.service;
|
package com.xxl.job.admin.service;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.client.OAuth2Client;
|
||||||
|
import com.xxl.job.admin.client.dto.CommonResult;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||||
|
import com.xxl.job.admin.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||||
import com.xxl.job.admin.core.util.CookieUtil;
|
import com.xxl.job.admin.core.util.CookieUtil;
|
||||||
import com.xxl.job.admin.core.util.I18nUtil;
|
import com.xxl.job.admin.core.util.I18nUtil;
|
||||||
import com.xxl.job.admin.core.util.JacksonUtil;
|
import com.xxl.job.admin.core.util.JacksonUtil;
|
||||||
import com.xxl.job.admin.dao.XxlJobUserDao;
|
import com.xxl.job.admin.dao.XxlJobUserDao;
|
||||||
|
import com.xxl.job.admin.framework.security.core.LoginUser;
|
||||||
|
import com.xxl.job.admin.framework.security.core.filter.TokenAuthenticationFilter;
|
||||||
|
import com.xxl.job.admin.framework.security.core.handler.AccessDeniedHandlerImpl;
|
||||||
|
import com.xxl.job.admin.framework.security.core.util.SecurityUtils;
|
||||||
import com.xxl.job.core.biz.model.ReturnT;
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@ -21,7 +31,12 @@ import java.math.BigInteger;
|
|||||||
public class LoginService {
|
public class LoginService {
|
||||||
|
|
||||||
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
|
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
|
||||||
|
public static final String ACCESS_TOKEN = "ACCESS_TOKEN";
|
||||||
|
public static final String REFRESH_TOKEN = "REFRESH_TOKEN";
|
||||||
|
public static final String LUNDU_LOGIN = "LUNDU_LOGIN";
|
||||||
|
public static final String COOKIE_PATH = "/xxl-job-admin";
|
||||||
|
@Resource
|
||||||
|
private OAuth2Client oauth2Client;
|
||||||
@Resource
|
@Resource
|
||||||
private XxlJobUserDao xxlJobUserDao;
|
private XxlJobUserDao xxlJobUserDao;
|
||||||
|
|
||||||
@ -31,6 +46,7 @@ public class LoginService {
|
|||||||
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
|
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
|
||||||
return tokenHex;
|
return tokenHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private XxlJobUser parseToken(String tokenHex) {
|
private XxlJobUser parseToken(String tokenHex) {
|
||||||
XxlJobUser xxlJobUser = null;
|
XxlJobUser xxlJobUser = null;
|
||||||
if (tokenHex != null) {
|
if (tokenHex != null) {
|
||||||
@ -112,4 +128,54 @@ public class LoginService {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否登录授权
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @return java.lang.Boolean
|
||||||
|
*/
|
||||||
|
public Boolean ifAuthorizedLogin(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
String accessToken = CookieUtil.getValue(request, ACCESS_TOKEN);
|
||||||
|
String refreshToken = CookieUtil.getValue(request, REFRESH_TOKEN);
|
||||||
|
String loginState = CookieUtil.getValue(request, LUNDU_LOGIN);
|
||||||
|
if (loginState == null) {
|
||||||
|
CookieUtil.remove(request, response, ACCESS_TOKEN, COOKIE_PATH);
|
||||||
|
CookieUtil.remove(request, response, REFRESH_TOKEN, COOKIE_PATH);
|
||||||
|
return false;
|
||||||
|
} else if (accessToken == null && refreshToken == null) {
|
||||||
|
// 如果未登录授权过 需要跳转登录授权页面
|
||||||
|
return false;
|
||||||
|
} else if (accessToken == null) {
|
||||||
|
// 刷新令牌 不需要跳转登录授权页面
|
||||||
|
OAuth2AccessTokenRespDTO refreshData = oauth2Client.refreshToken(refreshToken).getData();
|
||||||
|
CookieUtil.set(response, ACCESS_TOKEN, refreshData.getAccessToken(), null, "/xxl-job-admin", refreshData.getExpiresIn().intValue(), true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 基于 token 构建登录用户
|
||||||
|
LoginUser loginUser = buildLoginUserByToken(accessToken);
|
||||||
|
// 设置当前用户
|
||||||
|
if (loginUser != null) {
|
||||||
|
SecurityUtils.setLoginUser(loginUser, request);
|
||||||
|
}
|
||||||
|
// 令牌未过期不需要重新登录
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginUser buildLoginUserByToken(String token) {
|
||||||
|
try {
|
||||||
|
CommonResult<OAuth2CheckTokenRespDTO> accessTokenResult = oauth2Client.checkToken(token);
|
||||||
|
OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData();
|
||||||
|
if (accessToken == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 构建登录用户
|
||||||
|
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||||
|
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
|
||||||
|
.setAccessToken(accessToken.getAccessToken());
|
||||||
|
} catch (Exception exception) {
|
||||||
|
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,6 +482,8 @@ public class XxlJobServiceImpl implements XxlJobService {
|
|||||||
public PageResult<JobInfoRespDTO> apiPage(Integer pageNo, Integer pageSize, String name, Integer status, String handlerName) {
|
public PageResult<JobInfoRespDTO> apiPage(Integer pageNo, Integer pageSize, String name, Integer status, String handlerName) {
|
||||||
PageResult<JobInfoRespDTO> pageResult = new PageResult<>();
|
PageResult<JobInfoRespDTO> pageResult = new PageResult<>();
|
||||||
if (status != null && status == 2) status = 0;
|
if (status != null && status == 2) status = 0;
|
||||||
|
// 计算起始页数
|
||||||
|
pageNo = (pageNo - 1) * pageSize;
|
||||||
pageResult.setList(xxlJobInfoDao.apiPage(pageNo, pageSize, name, status, handlerName));
|
pageResult.setList(xxlJobInfoDao.apiPage(pageNo, pageSize, name, status, handlerName));
|
||||||
pageResult.setTotal(xxlJobInfoDao.apiPageCount(name, status, handlerName));
|
pageResult.setTotal(xxlJobInfoDao.apiPageCount(name, status, handlerName));
|
||||||
return pageResult;
|
return pageResult;
|
||||||
|
@ -39,10 +39,7 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
t
|
t.id,
|
||||||
.
|
|
||||||
id
|
|
||||||
,
|
|
||||||
t.job_group,
|
t.job_group,
|
||||||
t.job_desc,
|
t.job_desc,
|
||||||
t.add_time,
|
t.add_time,
|
||||||
@ -276,7 +273,7 @@
|
|||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
<if test="pageSize > 0">
|
<if test="pageSize > 0">
|
||||||
LIMIT #{pageSize} OFFSET ${(pageNo - 1) * pageSize}
|
LIMIT #{pageNo}, #{pageSize}
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="pageList" resultMap="XxlJobLog">
|
<select id="pageList" resultMap="XxlJobLog">
|
||||||
SELECT <include refid="Base_Column_List" />
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
FROM xxl_job_log AS t
|
FROM xxl_job_log AS t
|
||||||
<trim prefix="WHERE" prefixOverrides="AND | OR">
|
<trim prefix="WHERE" prefixOverrides="AND | OR">
|
||||||
<if test="jobId==0 and jobGroup gt 0">
|
<if test="jobId==0 and jobGroup gt 0">
|
||||||
@ -87,10 +88,12 @@
|
|||||||
<result column="trigger_time" property="beginTime"/>
|
<result column="trigger_time" property="beginTime"/>
|
||||||
<result column="handle_time" property="endTime"/>
|
<result column="handle_time" property="endTime"/>
|
||||||
<result column="duration" property="duration"/>
|
<result column="duration" property="duration"/>
|
||||||
<result column="alarm_status" property="status"/>
|
<result column="status" property="status"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<select id="apiPageList" resultMap="ApiXxlJobLog">
|
<select id="apiPageList" resultMap="ApiXxlJobLog">
|
||||||
SELECT <include refid="Base_Column_List" />, ROW_NUMBER() OVER (ORDER BY t.trigger_time) AS 'index', (t.handle_time -t.trigger_time) AS 'duration'
|
SELECT<include refid="Base_Column_List"/>, ROW_NUMBER() OVER (ORDER BY t.trigger_time) AS 'index',
|
||||||
|
(t.handle_time -t.trigger_time) AS 'duration',
|
||||||
|
IF(t.handle_code = 200, 1, 2) AS 'status'
|
||||||
FROM xxl_job_log AS t
|
FROM xxl_job_log AS t
|
||||||
<trim prefix="WHERE" prefixOverrides="AND | OR">
|
<trim prefix="WHERE" prefixOverrides="AND | OR">
|
||||||
<if test="jobId==0 and jobGroup gt 0">
|
<if test="jobId==0 and jobGroup gt 0">
|
||||||
@ -118,9 +121,14 @@
|
|||||||
AND t.trigger_code = 200
|
AND t.trigger_code = 200
|
||||||
AND t.handle_code = 0
|
AND t.handle_code = 0
|
||||||
</if>
|
</if>
|
||||||
|
<if test="handlerName != null">
|
||||||
|
AND t.handlerName LIKE CONCAT('%', #{handlerName}, '%')
|
||||||
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
ORDER BY t.trigger_time DESC
|
ORDER BY t.trigger_time DESC
|
||||||
|
<if test="pagesize > 0">
|
||||||
LIMIT #{offset}, #{pagesize}
|
LIMIT #{offset}, #{pagesize}
|
||||||
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="pageListCount" resultType="int">
|
<select id="pageListCount" resultType="int">
|
||||||
@ -154,9 +162,44 @@
|
|||||||
</if>
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
</select>
|
</select>
|
||||||
|
<select id="apiPageListCount" resultType="int">
|
||||||
|
SELECT count(1)
|
||||||
|
FROM xxl_job_log AS t
|
||||||
|
<trim prefix="WHERE" prefixOverrides="AND | OR">
|
||||||
|
<if test="jobId==0 and jobGroup gt 0">
|
||||||
|
AND t.job_group = #{jobGroup}
|
||||||
|
</if>
|
||||||
|
<if test="jobId gt 0">
|
||||||
|
AND t.job_id = #{jobId}
|
||||||
|
</if>
|
||||||
|
<if test="triggerTimeStart != null">
|
||||||
|
AND t.trigger_time <![CDATA[ >= ]]> #{triggerTimeStart}
|
||||||
|
</if>
|
||||||
|
<if test="triggerTimeEnd != null">
|
||||||
|
AND t.trigger_time <![CDATA[ <= ]]> #{triggerTimeEnd}
|
||||||
|
</if>
|
||||||
|
<if test="logStatus == 1">
|
||||||
|
AND t.handle_code = 200
|
||||||
|
</if>
|
||||||
|
<if test="logStatus == 2">
|
||||||
|
AND (
|
||||||
|
t.trigger_code NOT IN (0, 200) OR
|
||||||
|
t.handle_code NOT IN (0, 200)
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
<if test="logStatus == 3">
|
||||||
|
AND t.trigger_code = 200
|
||||||
|
AND t.handle_code = 0
|
||||||
|
</if>
|
||||||
|
<if test="handlerName != null">
|
||||||
|
AND t.executor_handler LIKE CONCAT('%', #{handlerName}, '%')
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="load" parameterType="java.lang.Long" resultMap="XxlJobLog">
|
<select id="load" parameterType="java.lang.Long" resultMap="XxlJobLog">
|
||||||
SELECT <include refid="Base_Column_List" />
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
FROM xxl_job_log AS t
|
FROM xxl_job_log AS t
|
||||||
WHERE t.id = #{id}
|
WHERE t.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
@ -183,8 +226,7 @@
|
|||||||
|
|
||||||
<update id="updateTriggerInfo">
|
<update id="updateTriggerInfo">
|
||||||
UPDATE xxl_job_log
|
UPDATE xxl_job_log
|
||||||
SET
|
SET `trigger_time`= #{triggerTime},
|
||||||
`trigger_time`= #{triggerTime},
|
|
||||||
`trigger_code`= #{triggerCode},
|
`trigger_code`= #{triggerCode},
|
||||||
`trigger_msg`= #{triggerMsg},
|
`trigger_msg`= #{triggerMsg},
|
||||||
`executor_address`= #{executorAddress},
|
`executor_address`= #{executorAddress},
|
||||||
@ -197,15 +239,15 @@
|
|||||||
|
|
||||||
<update id="updateHandleInfo">
|
<update id="updateHandleInfo">
|
||||||
UPDATE xxl_job_log
|
UPDATE xxl_job_log
|
||||||
SET
|
SET `handle_time`= #{handleTime},
|
||||||
`handle_time`= #{handleTime},
|
|
||||||
`handle_code`= #{handleCode},
|
`handle_code`= #{handleCode},
|
||||||
`handle_msg`= #{handleMsg}
|
`handle_msg`= #{handleMsg}
|
||||||
WHERE `id` = #{id}
|
WHERE `id` = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<delete id="delete">
|
<delete id="delete">
|
||||||
delete from xxl_job_log
|
delete
|
||||||
|
from xxl_job_log
|
||||||
WHERE job_id = #{jobId}
|
WHERE job_id = #{jobId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
@ -222,8 +264,7 @@
|
|||||||
</select>-->
|
</select>-->
|
||||||
|
|
||||||
<select id="findLogReport" resultType="java.util.Map">
|
<select id="findLogReport" resultType="java.util.Map">
|
||||||
SELECT
|
SELECT COUNT(handle_code) triggerDayCount,
|
||||||
COUNT(handle_code) triggerDayCount,
|
|
||||||
SUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,
|
SUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,
|
||||||
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
|
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
|
||||||
FROM xxl_job_log
|
FROM xxl_job_log
|
||||||
@ -273,9 +314,12 @@
|
|||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<select id="findFailJobLogIds" resultType="long">
|
<select id="findFailJobLogIds" resultType="long">
|
||||||
SELECT id FROM `xxl_job_log`
|
SELECT id
|
||||||
|
FROM `xxl_job_log`
|
||||||
WHERE !(
|
WHERE !(
|
||||||
(trigger_code in (0, 200) and handle_code = 0)
|
(trigger_code in (0
|
||||||
|
, 200)
|
||||||
|
and handle_code = 0)
|
||||||
OR
|
OR
|
||||||
(handle_code = 200)
|
(handle_code = 200)
|
||||||
)
|
)
|
||||||
@ -286,19 +330,16 @@
|
|||||||
|
|
||||||
<update id="updateAlarmStatus">
|
<update id="updateAlarmStatus">
|
||||||
UPDATE xxl_job_log
|
UPDATE xxl_job_log
|
||||||
SET
|
SET `alarm_status` = #{newAlarmStatus}
|
||||||
`alarm_status` = #{newAlarmStatus}
|
WHERE `id` = #{logId}
|
||||||
WHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus}
|
AND `alarm_status` = #{oldAlarmStatus}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="findLostJobIds" resultType="long">
|
<select id="findLostJobIds" resultType="long">
|
||||||
SELECT
|
SELECT t.id
|
||||||
t.id
|
FROM xxl_job_log t
|
||||||
FROM
|
|
||||||
xxl_job_log t
|
|
||||||
LEFT JOIN xxl_job_registry t2 ON t.executor_address = t2.registry_value
|
LEFT JOIN xxl_job_registry t2 ON t.executor_address = t2.registry_value
|
||||||
WHERE
|
WHERE t.trigger_code = 200
|
||||||
t.trigger_code = 200
|
|
||||||
AND t.handle_code = 0
|
AND t.handle_code = 0
|
||||||
AND t.trigger_time <![CDATA[ <= ]]> #{losedTime}
|
AND t.trigger_time <![CDATA[ <= ]]> #{losedTime}
|
||||||
AND t2.id IS NULL;
|
AND t2.id IS NULL;
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
$(function(){
|
$(function(){
|
||||||
|
// 获取当前登录用户信息
|
||||||
|
$.get(base_url + "/auth/get", function(data, status) {
|
||||||
|
if (data.code !== 0) {
|
||||||
|
alert('获得个人信息失败,原因:' + result.msg)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$('#authUsername').text(data.data.nickname);
|
||||||
|
});
|
||||||
// logout
|
// logout
|
||||||
$("#logoutBtn").click(function(){
|
$("#logoutBtn").click(function(){
|
||||||
layer.confirm( I18n.logout_confirm , {
|
layer.confirm( I18n.logout_confirm , {
|
||||||
@ -8,8 +15,15 @@ $(function(){
|
|||||||
btn: [ I18n.system_ok, I18n.system_cancel ]
|
btn: [ I18n.system_ok, I18n.system_cancel ]
|
||||||
}, function(index){
|
}, function(index){
|
||||||
layer.close(index);
|
layer.close(index);
|
||||||
|
// 直接清理cookie,直接设置过期
|
||||||
$.post(base_url + "/logout", function(data, status) {
|
document.cookie = "ACCESS_TOKEN=; max-age=0; path=/xxl-job-admin";
|
||||||
|
document.cookie = "REFRESH_TOKEN=; max-age=0; path=/xxl-job-admin";
|
||||||
|
layer.open({
|
||||||
|
icon: '2',
|
||||||
|
title: I18n.system_tips,
|
||||||
|
content: ('已退出登录请关闭当前会话框!' || I18n.logout_success)
|
||||||
|
});
|
||||||
|
/*$.post(base_url + "/logout", function(data, status) {
|
||||||
if (data.code == "200") {
|
if (data.code == "200") {
|
||||||
layer.msg( I18n.logout_success );
|
layer.msg( I18n.logout_success );
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
@ -23,7 +37,7 @@ $(function(){
|
|||||||
icon: '2'
|
icon: '2'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -63,6 +63,9 @@ $(function() {
|
|||||||
'glueSource' : glueSource,
|
'glueSource' : glueSource,
|
||||||
'glueRemark' : glueRemark
|
'glueRemark' : glueRemark
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
|
@ -8,6 +8,9 @@ $(function() {
|
|||||||
"ajax": {
|
"ajax": {
|
||||||
url: base_url + "/jobgroup/pageList",
|
url: base_url + "/jobgroup/pageList",
|
||||||
type:"post",
|
type:"post",
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
data : function ( d ) {
|
data : function ( d ) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.appname = $('#appname').val();
|
obj.appname = $('#appname').val();
|
||||||
@ -166,6 +169,9 @@ $(function() {
|
|||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : base_url + '/jobgroup/remove',
|
url : base_url + '/jobgroup/remove',
|
||||||
data : {"id":id},
|
data : {"id":id},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
|
@ -8,6 +8,9 @@ $(function() {
|
|||||||
"ajax": {
|
"ajax": {
|
||||||
url: base_url + "/jobinfo/pageList",
|
url: base_url + "/jobinfo/pageList",
|
||||||
type:"post",
|
type:"post",
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
data : function ( d ) {
|
data : function ( d ) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.jobGroup = $('#jobGroup').val();
|
obj.jobGroup = $('#jobGroup').val();
|
||||||
@ -243,6 +246,9 @@ $(function() {
|
|||||||
data : {
|
data : {
|
||||||
"id" : id
|
"id" : id
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
@ -278,6 +284,9 @@ $(function() {
|
|||||||
"executorParam" : $("#jobTriggerModal .textarea[name='executorParam']").val(),
|
"executorParam" : $("#jobTriggerModal .textarea[name='executorParam']").val(),
|
||||||
"addressList" : $("#jobTriggerModal .textarea[name='addressList']").val()
|
"addressList" : $("#jobTriggerModal .textarea[name='addressList']").val()
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
@ -308,6 +317,9 @@ $(function() {
|
|||||||
data : {
|
data : {
|
||||||
"id" : jobGroup
|
"id" : jobGroup
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
|
|
||||||
@ -342,6 +354,9 @@ $(function() {
|
|||||||
"scheduleType" : row.scheduleType,
|
"scheduleType" : row.scheduleType,
|
||||||
"scheduleConf" : row.scheduleConf
|
"scheduleConf" : row.scheduleConf
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ $(function() {
|
|||||||
"logId":logId,
|
"logId":logId,
|
||||||
"fromLineNum":fromLineNum
|
"fromLineNum":fromLineNum
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@ $(function() {
|
|||||||
async: false, // async, avoid js invoke pagelist before jobId data init
|
async: false, // async, avoid js invoke pagelist before jobId data init
|
||||||
url : base_url + '/joblog/getJobsByGroup',
|
url : base_url + '/joblog/getJobsByGroup',
|
||||||
data : {"jobGroup":jobGroup},
|
data : {"jobGroup":jobGroup},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
@ -77,6 +80,9 @@ $(function() {
|
|||||||
"ajax": {
|
"ajax": {
|
||||||
url: base_url + "/joblog/pageList" ,
|
url: base_url + "/joblog/pageList" ,
|
||||||
type:"post",
|
type:"post",
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
data : function ( d ) {
|
data : function ( d ) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.jobGroup = $('#jobGroup').val();
|
obj.jobGroup = $('#jobGroup').val();
|
||||||
@ -279,6 +285,9 @@ $(function() {
|
|||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : base_url + '/joblog/logKill',
|
url : base_url + '/joblog/logKill',
|
||||||
data : {"id":_id},
|
data : {"id":_id},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
|
@ -8,6 +8,9 @@ $(function() {
|
|||||||
"ajax": {
|
"ajax": {
|
||||||
url: base_url + "/user/pageList",
|
url: base_url + "/user/pageList",
|
||||||
type:"post",
|
type:"post",
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
data : function ( d ) {
|
data : function ( d ) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.username = $('#username').val();
|
obj.username = $('#username').val();
|
||||||
@ -124,6 +127,9 @@ $(function() {
|
|||||||
data : {
|
data : {
|
||||||
"id" : id
|
"id" : id
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
|
@ -644,6 +644,9 @@
|
|||||||
"scheduleType" : 'CRON',
|
"scheduleType" : 'CRON',
|
||||||
"scheduleConf" : inputElement.val()
|
"scheduleConf" : inputElement.val()
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
|
@ -644,6 +644,9 @@
|
|||||||
"scheduleType" : 'CRON',
|
"scheduleType" : 'CRON',
|
||||||
"scheduleConf" : inputElement.val()
|
"scheduleConf" : inputElement.val()
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + localStorage.getItem('ACCESS-TOKEN')
|
||||||
|
},
|
||||||
dataType : "json",
|
dataType : "json",
|
||||||
success : function(data){
|
success : function(data){
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
|
@ -84,11 +84,12 @@
|
|||||||
<#-- login user -->
|
<#-- login user -->
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||||
${I18n.system_welcome} ${Request["XXL_JOB_LOGIN_IDENTITY"].username}
|
<#-- ${I18n.system_welcome} ${Request["XXL_JOB_LOGIN_IDENTITY"].username}-->
|
||||||
|
${I18n.system_welcome} <span id="authUsername"></span>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
<li id="updatePwd" ><a href="javascript:">${I18n.change_pwd}</a></li>
|
<#-- <li id="updatePwd" ><a href="javascript:">${I18n.change_pwd}</a></li>-->
|
||||||
<li id="logoutBtn" ><a href="javascript:">${I18n.logout_btn}</a></li>
|
<li id="logoutBtn" ><a href="javascript:">${I18n.logout_btn}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
@ -7,39 +7,98 @@
|
|||||||
<title>${I18n.admin_name}</title>
|
<title>${I18n.admin_name}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="hold-transition login-page">
|
<body class="hold-transition login-page">
|
||||||
<div class="login-box">
|
<#-- <div class="login-box">-->
|
||||||
<div class="login-logo">
|
<#-- <div class="login-logo">-->
|
||||||
<a><b>XXL</b>JOB</a>
|
<#-- <a><b>XXL</b>JOB</a>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
<form id="loginForm" method="post" >
|
<#-- <form id="loginForm" method="post" >-->
|
||||||
<div class="login-box-body">
|
<#-- <div class="login-box-body">-->
|
||||||
<p class="login-box-msg">${I18n.admin_name}</p>
|
<#-- <p class="login-box-msg">${I18n.admin_name}</p>-->
|
||||||
<div class="form-group has-feedback">
|
<#-- <div class="form-group has-feedback">-->
|
||||||
<input type="text" name="userName" class="form-control" placeholder="${I18n.login_username_placeholder}" maxlength="18" >
|
<#-- <input type="text" name="userName" class="form-control" placeholder="${I18n.login_username_placeholder}" maxlength="18" >-->
|
||||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
<#-- <span class="glyphicon glyphicon-envelope form-control-feedback"></span>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
<div class="form-group has-feedback">
|
<#-- <div class="form-group has-feedback">-->
|
||||||
<input type="password" name="password" class="form-control" placeholder="${I18n.login_password_placeholder}" maxlength="18" >
|
<#-- <input type="password" name="password" class="form-control" placeholder="${I18n.login_password_placeholder}" maxlength="18" >-->
|
||||||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
<#-- <span class="glyphicon glyphicon-lock form-control-feedback"></span>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
<div class="row">
|
<#-- <div class="row">-->
|
||||||
<div class="col-xs-8">
|
<#-- <div class="col-xs-8">-->
|
||||||
<div class="checkbox icheck">
|
<#-- <div class="checkbox icheck">-->
|
||||||
<label>
|
<#-- <label>-->
|
||||||
<input type="checkbox" name="ifRemember" > ${I18n.login_remember_me}
|
<#-- <input type="checkbox" name="ifRemember" > ${I18n.login_remember_me}-->
|
||||||
</label>
|
<#-- </label>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
</div><!-- /.col -->
|
<#-- </div><!-- /.col –>-->
|
||||||
<div class="col-xs-4">
|
<#-- <div class="col-xs-4">-->
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-flat">${I18n.login_btn}</button>
|
<#-- <button type="submit" class="btn btn-primary btn-block btn-flat">${I18n.login_btn}</button>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
</form>
|
<#-- </form>-->
|
||||||
</div>
|
<#-- </div>-->
|
||||||
<@netCommon.commonScript />
|
<@netCommon.commonScript />
|
||||||
<script src="${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js"></script>
|
<#--<script src="${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js"></script>-->
|
||||||
<script src="${request.contextPath}/static/js/login.1.js"></script>
|
<#--<script src="${request.contextPath}/static/js/login.1.js"></script>-->
|
||||||
|
<script src="${request.contextPath}/static/adminlte/bower_components/jquery/jquery.min.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 跳转单点登录
|
||||||
|
*/
|
||||||
|
function ssoLogin() {
|
||||||
|
const clientId = 'ludu-job-admin'; // 可以改写成,你的 clientId
|
||||||
|
const redirectUri = encodeURIComponent('http://127.0.0.1:9090/xxl-job-admin/toLogin'); // 注意,需要使用 encodeURIComponent 编码地址
|
||||||
|
const responseType = 'code'; // 1)授权码模式,对应 code;2)简化模式,对应 token
|
||||||
|
window.location.href = 'http://127.0.0.1:80/sso?client_id=' + clientId
|
||||||
|
+ '&redirect_uri=' + redirectUri
|
||||||
|
+ '&response_type=' + responseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取 cookie
|
||||||
|
const accessToken = document.cookie
|
||||||
|
.replace(/(?:(?:^|.*;\s*)ACCESS_TOKEN\s*\=\s*([^;]*).*$)|^.*$/, "$1");
|
||||||
|
const refreshToken = document.cookie
|
||||||
|
.replace(/(?:(?:^|.*;\s*)REFRESH_TOKEN\s*\=\s*([^;]*).*$)|^.*$/, "$1");
|
||||||
|
// 情况一:未登录
|
||||||
|
if (!accessToken) {
|
||||||
|
// 获取 URL 中的查询参数
|
||||||
|
let urlParams = new URLSearchParams(window.location.search);
|
||||||
|
// 获取 code 参数的值
|
||||||
|
let code = urlParams.get('code');
|
||||||
|
if (!code) {
|
||||||
|
ssoLogin();
|
||||||
|
} else {
|
||||||
|
// 提交
|
||||||
|
const redirectUri = 'http://127.0.0.1:9090/xxl-job-admin/toLogin'; // 需要修改成,你回调的地址,就是在 index.html 拼接的 redirectUri
|
||||||
|
$.ajax({
|
||||||
|
url: "http://127.0.0.1:9090/xxl-job-admin/auth/login-by-code?code=" + code
|
||||||
|
+ '&redirectUri=' + redirectUri,
|
||||||
|
method: 'POST',
|
||||||
|
success: function (result) {
|
||||||
|
if (result.code !== 0) {
|
||||||
|
// layer.open({
|
||||||
|
// title: I18n.system_tips,
|
||||||
|
// btn: [ I18n.system_ok ],
|
||||||
|
// content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)),
|
||||||
|
// icon: '2'
|
||||||
|
// });
|
||||||
|
alert('获得访问令牌失败,原因:' + result.msg)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置cookie
|
||||||
|
document.cookie = "ACCESS_TOKEN=" + result.data.access_token + "; max-age=" + (result.data.expires_in - 20) + "; path=/xxl-job-admin";
|
||||||
|
document.cookie = "REFRESH_TOKEN=" + result.data.refresh_token + "; max-age=43000; path=/xxl-job-admin";
|
||||||
|
// 跳转回首页
|
||||||
|
window.location.href = '/xxl-job-admin';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 情况三:已登录
|
||||||
|
else {
|
||||||
|
window.location.href = '/xxl-job-admin';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>ludu-module-sampling</artifactId>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>ludu-module-sampling-api</artifactId>
|
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
|
||||||
<description>
|
|
||||||
ticket 模块 API,暴露给其它模块调用
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-common</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springdoc</groupId>
|
|
||||||
<artifactId>springdoc-openapi-ui</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 参数校验 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- RPC 远程调用相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,160 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>ludu-module-sampling</artifactId>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>ludu-module-sampling-biz</artifactId>
|
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
|
||||||
<description>
|
|
||||||
sampling 模块,我们抽数模块。
|
|
||||||
例如说:检票和售票的数据抽数等等
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- 定时任务 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>ludu-job-core</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- 测试调用票务API -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>ludu-module-ticket-manager-api</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- 依赖服务 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>ludu-module-sampling-api</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Spring Cloud 基础 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-env</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-module-system-api</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-module-infra-api</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 业务组件 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-security</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- DB 相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-redis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- RPC 远程调用相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Registry 注册中心相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Config 配置中心相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 消息队列相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-mq</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Test 测试相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 工具类相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 监控相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<!-- 设置构建的 jar 包名 -->
|
|
||||||
<finalName>${project.artifactId}</finalName>
|
|
||||||
<plugins>
|
|
||||||
<!-- 打包 -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
<version>${spring.boot.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.sampling;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Description TODO
|
|
||||||
*/
|
|
||||||
@SpringBootApplication
|
|
||||||
public class SamplingServerApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(SamplingServerApplication.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.sampling.controller.admin.test;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.ticket.api.asset.TicketAssetApi;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Description TODO
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/sampling")
|
|
||||||
@Valid
|
|
||||||
public class TestController {
|
|
||||||
@Autowired
|
|
||||||
private TicketAssetApi ticketAssetApi;
|
|
||||||
@RequestMapping("/test")
|
|
||||||
public void test(){
|
|
||||||
System.out.println(ticketAssetApi.countAsset());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.sampling.framework.rpc.config;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.ticket.api.asset.TicketAssetApi;
|
|
||||||
import cn.iocoder.yudao.module.ticket.api.checkticket.TicketCheckTicketApi;
|
|
||||||
import cn.iocoder.yudao.module.ticket.api.saledata.TicketSaleDataApi;
|
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Description TODO
|
|
||||||
*/
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@EnableFeignClients(clients = {TicketAssetApi.class, TicketSaleDataApi.class, TicketCheckTicketApi.class})
|
|
||||||
public class RpcConfiguration {
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.sampling.framework.security.config;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
|
|
||||||
import cn.iocoder.yudao.module.system.enums.ApiConstants;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Demo 模块的 Security 配置
|
|
||||||
*/
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
public class SecurityConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
|
||||||
return new AuthorizeRequestsCustomizer() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
|
|
||||||
// Swagger 接口文档
|
|
||||||
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
|
|
||||||
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
|
|
||||||
// Druid 监控
|
|
||||||
registry.antMatchers("/druid/**").anonymous();
|
|
||||||
// Spring Boot Actuator 的安全配置
|
|
||||||
registry.antMatchers("/actuator").anonymous()
|
|
||||||
.antMatchers("/actuator/**").anonymous();
|
|
||||||
// RPC 服务的安全配置
|
|
||||||
registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
spring:
|
|
||||||
main:
|
|
||||||
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
|
|
||||||
allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务
|
|
||||||
|
|
||||||
# Servlet 配置
|
|
||||||
servlet:
|
|
||||||
# 文件上传相关配置项
|
|
||||||
multipart:
|
|
||||||
max-file-size: 16MB # 单个文件大小
|
|
||||||
max-request-size: 32MB # 设置总上传的文件大小
|
|
||||||
mvc:
|
|
||||||
pathmatch:
|
|
||||||
matching-strategy: ANT_PATH_MATCHER # 解决 SpringFox 与 SpringBoot 2.6.x 不兼容的问题,参见 SpringFoxHandlerProviderBeanPostProcessor 类
|
|
||||||
|
|
||||||
# Jackson 配置项
|
|
||||||
jackson:
|
|
||||||
serialization:
|
|
||||||
write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
|
|
||||||
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
|
|
||||||
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
|
|
||||||
fail-on-empty-beans: false # 允许序列化无属性的 Bean
|
|
||||||
|
|
||||||
# Cache 配置项
|
|
||||||
cache:
|
|
||||||
type: REDIS
|
|
||||||
redis:
|
|
||||||
time-to-live: 1h # 设置过期时间为 1 小时
|
|
||||||
|
|
||||||
--- #################### 接口文档配置 ####################
|
|
||||||
|
|
||||||
springdoc:
|
|
||||||
api-docs:
|
|
||||||
enabled: true # 1. 是否开启 Swagger 接文档的元数据
|
|
||||||
path: /v3/api-docs
|
|
||||||
swagger-ui:
|
|
||||||
enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面
|
|
||||||
path: /swagger-ui.html
|
|
||||||
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
|
|
||||||
|
|
||||||
knife4j:
|
|
||||||
enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面
|
|
||||||
setting:
|
|
||||||
language: zh_cn
|
|
||||||
|
|
||||||
# MyBatis Plus 的配置项
|
|
||||||
mybatis-plus:
|
|
||||||
configuration:
|
|
||||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
|
||||||
global-config:
|
|
||||||
db-config:
|
|
||||||
id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
|
||||||
# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
|
|
||||||
# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
|
||||||
# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
|
|
||||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
|
||||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
|
||||||
banner: false # 关闭控制台的 Banner 打印
|
|
||||||
type-aliases-package: ${yudao.info.base-package}.dal.dataobject
|
|
||||||
encryptor:
|
|
||||||
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
|
|
||||||
|
|
||||||
mybatis-plus-join:
|
|
||||||
banner: false # 关闭控制台的 Banner 打印
|
|
||||||
|
|
||||||
# Spring Data Redis 配置
|
|
||||||
spring:
|
|
||||||
data:
|
|
||||||
redis:
|
|
||||||
repositories:
|
|
||||||
enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度
|
|
||||||
|
|
||||||
# VO 转换(数据翻译)相关
|
|
||||||
easy-trans:
|
|
||||||
is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口
|
|
||||||
is-enable-cloud: false # 禁用 TransType.RPC 微服务模式
|
|
||||||
|
|
||||||
--- #################### RPC 远程调用相关配置 ####################
|
|
||||||
|
|
||||||
--- #################### MQ 消息队列相关配置 ####################
|
|
||||||
|
|
||||||
--- #################### 定时任务相关配置 ####################
|
|
||||||
|
|
||||||
xxl:
|
|
||||||
job:
|
|
||||||
admin:
|
|
||||||
addresses: http://127.0.0.1:9090/xxl-job-admin
|
|
||||||
executor:
|
|
||||||
appname: ${spring.application.name} # 执行器 AppName
|
|
||||||
address:
|
|
||||||
ip: # 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
|
||||||
port: 0 # ### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
|
||||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
|
||||||
logretentiondays: 30 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
|
||||||
accessToken: # 执行器通讯TOKEN
|
|
||||||
|
|
||||||
--- #################### 芋道相关配置 ####################
|
|
||||||
|
|
||||||
yudao:
|
|
||||||
info:
|
|
||||||
version: 1.0.0
|
|
||||||
base-package: cn.iocoder.yudao.module.sampling
|
|
||||||
swagger:
|
|
||||||
title: 管理后台
|
|
||||||
description: 提供管理员管理的所有功能
|
|
||||||
version: ${yudao.info.version}
|
|
||||||
base-package: ${yudao.info.base-package}
|
|
||||||
captcha:
|
|
||||||
enable: true # 验证码的开关,默认为 true;
|
|
||||||
tenant: # 多租户相关配置项
|
|
||||||
enable: false
|
|
||||||
ignore-urls:
|
|
||||||
ignore-tables:
|
|
||||||
|
|
||||||
debug: false
|
|
@ -1,14 +0,0 @@
|
|||||||
spring:
|
|
||||||
application:
|
|
||||||
name: sampling-server
|
|
||||||
|
|
||||||
profiles:
|
|
||||||
active: local
|
|
||||||
|
|
||||||
server:
|
|
||||||
port: 48089
|
|
||||||
|
|
||||||
# 日志文件配置。注意,如果 logging.file.name 不放在 bootstrap.yaml 配置文件,而是放在 application.yaml 中,会导致出现 LOG_FILE_IS_UNDEFINED 文件
|
|
||||||
logging:
|
|
||||||
file:
|
|
||||||
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
|
|
@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>yudao</artifactId>
|
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<modules>
|
|
||||||
<module>ludu-module-sampling-api</module>
|
|
||||||
<module>ludu-module-sampling-biz</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<artifactId>ludu-module-sampling</artifactId>
|
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
|
||||||
<description>
|
|
||||||
sampling 模块,我们放抽数服务。
|
|
||||||
</description>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,103 +0,0 @@
|
|||||||
--- #################### 数据库相关配置 ####################
|
|
||||||
spring:
|
|
||||||
# 数据源配置项
|
|
||||||
autoconfigure:
|
|
||||||
exclude:
|
|
||||||
- com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
|
|
||||||
datasource:
|
|
||||||
druid: # Druid 【监控】相关的全局配置
|
|
||||||
web-stat-filter:
|
|
||||||
enabled: true
|
|
||||||
stat-view-servlet:
|
|
||||||
enabled: true
|
|
||||||
allow: # 设置白名单,不填则允许所有访问
|
|
||||||
url-pattern: /druid/*
|
|
||||||
login-username: # 控制台管理用户名和密码
|
|
||||||
login-password:
|
|
||||||
filter:
|
|
||||||
stat:
|
|
||||||
enabled: true
|
|
||||||
log-slow-sql: true # 慢 SQL 记录
|
|
||||||
slow-sql-millis: 100
|
|
||||||
merge-sql: true
|
|
||||||
wall:
|
|
||||||
config:
|
|
||||||
multi-statement-allow: true
|
|
||||||
dynamic: # 多数据源配置
|
|
||||||
druid: # Druid 【连接池】相关的全局配置
|
|
||||||
initial-size: 5 # 初始连接数
|
|
||||||
min-idle: 10 # 最小连接池数量
|
|
||||||
max-active: 20 # 最大连接池数量
|
|
||||||
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
|
|
||||||
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
|
|
||||||
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
|
|
||||||
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
|
|
||||||
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
|
|
||||||
test-while-idle: true
|
|
||||||
test-on-borrow: false
|
|
||||||
test-on-return: false
|
|
||||||
primary: master
|
|
||||||
datasource:
|
|
||||||
master:
|
|
||||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
|
||||||
username: root
|
|
||||||
password: 123456
|
|
||||||
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
|
|
||||||
lazy: true # 开启懒加载,保证启动速度
|
|
||||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
|
||||||
username: root
|
|
||||||
password: 123456
|
|
||||||
|
|
||||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
|
||||||
redis:
|
|
||||||
host: 400-infra.server.iocoder.cn # 地址
|
|
||||||
port: 6379 # 端口
|
|
||||||
database: 1 # 数据库索引
|
|
||||||
# password: 123456 # 密码,建议生产环境开启
|
|
||||||
|
|
||||||
--- #################### MQ 消息队列相关配置 ####################
|
|
||||||
|
|
||||||
--- #################### 定时任务相关配置 ####################
|
|
||||||
xxl:
|
|
||||||
job:
|
|
||||||
admin:
|
|
||||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
|
||||||
|
|
||||||
--- #################### 服务保障相关配置 ####################
|
|
||||||
|
|
||||||
# Lock4j 配置项
|
|
||||||
lock4j:
|
|
||||||
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
|
||||||
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
|
||||||
|
|
||||||
--- #################### 监控相关配置 ####################
|
|
||||||
|
|
||||||
# Actuator 监控端点的配置项
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
|
|
||||||
exposure:
|
|
||||||
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
|
|
||||||
|
|
||||||
# Spring Boot Admin 配置项
|
|
||||||
spring:
|
|
||||||
boot:
|
|
||||||
admin:
|
|
||||||
# Spring Boot Admin Client 客户端的相关配置
|
|
||||||
client:
|
|
||||||
instance:
|
|
||||||
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
|
|
||||||
# Spring Boot Admin Server 服务端的相关配置
|
|
||||||
context-path: /admin # 配置 Spring
|
|
||||||
|
|
||||||
--- #################### 芋道相关配置 ####################
|
|
||||||
|
|
||||||
# 芋道配置项,设置当前项目所有自定义的配置
|
|
||||||
yudao:
|
|
||||||
xss:
|
|
||||||
enable: false
|
|
||||||
web:
|
|
||||||
admin-ui:
|
|
||||||
url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
|
|
||||||
demo: true # 开启演示模式
|
|
@ -1,127 +0,0 @@
|
|||||||
--- #################### 数据库相关配置 ####################
|
|
||||||
spring:
|
|
||||||
# 数据源配置项
|
|
||||||
autoconfigure:
|
|
||||||
exclude:
|
|
||||||
- com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
|
|
||||||
- de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
|
|
||||||
datasource:
|
|
||||||
druid: # Druid 【监控】相关的全局配置
|
|
||||||
web-stat-filter:
|
|
||||||
enabled: true
|
|
||||||
stat-view-servlet:
|
|
||||||
enabled: true
|
|
||||||
allow: # 设置白名单,不填则允许所有访问
|
|
||||||
url-pattern: /druid/*
|
|
||||||
login-username: # 控制台管理用户名和密码
|
|
||||||
login-password:
|
|
||||||
filter:
|
|
||||||
stat:
|
|
||||||
enabled: true
|
|
||||||
log-slow-sql: true # 慢 SQL 记录
|
|
||||||
slow-sql-millis: 100
|
|
||||||
merge-sql: true
|
|
||||||
wall:
|
|
||||||
config:
|
|
||||||
multi-statement-allow: true
|
|
||||||
dynamic: # 多数据源配置
|
|
||||||
druid: # Druid 【连接池】相关的全局配置
|
|
||||||
initial-size: 1 # 初始连接数
|
|
||||||
min-idle: 1 # 最小连接池数量
|
|
||||||
max-active: 20 # 最大连接池数量
|
|
||||||
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
|
|
||||||
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
|
|
||||||
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
|
|
||||||
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
|
|
||||||
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
|
|
||||||
test-while-idle: true
|
|
||||||
test-on-borrow: false
|
|
||||||
test-on-return: false
|
|
||||||
primary: master
|
|
||||||
datasource:
|
|
||||||
master:
|
|
||||||
url: jdbc:mysql://120.46.37.243:3306/ludu_ticket?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
|
||||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
|
|
||||||
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
|
|
||||||
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
|
|
||||||
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例
|
|
||||||
# url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
|
|
||||||
username: root
|
|
||||||
password: xpower1234
|
|
||||||
# username: sa # SQL Server 连接的示例
|
|
||||||
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例
|
|
||||||
# username: SYSDBA # DM 连接的示例
|
|
||||||
# password: SYSDBA # DM 连接的示例
|
|
||||||
slave: # 模拟从库,可根据自己需要修改
|
|
||||||
lazy: true # 开启懒加载,保证启动速度
|
|
||||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
|
||||||
username: root
|
|
||||||
password: 123456
|
|
||||||
|
|
||||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
|
||||||
redis:
|
|
||||||
host: 127.0.0.1 # 地址
|
|
||||||
port: 6379 # 端口
|
|
||||||
database: 0 # 数据库索引
|
|
||||||
# password: 123456 # 密码,建议生产环境开启
|
|
||||||
|
|
||||||
--- #################### MQ 消息队列相关配置 ####################
|
|
||||||
|
|
||||||
--- #################### 定时任务相关配置 ####################
|
|
||||||
|
|
||||||
xxl:
|
|
||||||
job:
|
|
||||||
enabled: false # 是否开启调度中心,默认为 true 开启
|
|
||||||
admin:
|
|
||||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
|
||||||
|
|
||||||
--- #################### 服务保障相关配置 ####################
|
|
||||||
|
|
||||||
# Lock4j 配置项
|
|
||||||
lock4j:
|
|
||||||
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
|
||||||
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
|
||||||
|
|
||||||
--- #################### 监控相关配置 ####################
|
|
||||||
|
|
||||||
# Actuator 监控端点的配置项
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
|
|
||||||
exposure:
|
|
||||||
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
|
|
||||||
|
|
||||||
# Spring Boot Admin 配置项
|
|
||||||
spring:
|
|
||||||
boot:
|
|
||||||
admin:
|
|
||||||
# Spring Boot Admin Client 客户端的相关配置
|
|
||||||
client:
|
|
||||||
instance:
|
|
||||||
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
|
|
||||||
|
|
||||||
# 日志文件配置
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
# 配置自己写的 MyBatis Mapper 打印日志
|
|
||||||
cn.iocoder.yudao.module.system.dal.mysql: debug
|
|
||||||
cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper: INFO # 配置 SensitiveWordMapper 的日志级别为 info
|
|
||||||
cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info
|
|
||||||
|
|
||||||
--- #################### 芋道相关配置 ####################
|
|
||||||
|
|
||||||
# 芋道配置项,设置当前项目所有自定义的配置
|
|
||||||
yudao:
|
|
||||||
env: # 多环境的配置项
|
|
||||||
tag: ${HOSTNAME}
|
|
||||||
web:
|
|
||||||
admin-ui:
|
|
||||||
url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
|
|
||||||
security:
|
|
||||||
mock-enable: true
|
|
||||||
xss:
|
|
||||||
enable: false
|
|
||||||
access-log: # 访问日志的配置项
|
|
||||||
enable: false
|
|
||||||
demo: false # 关闭演示模式
|
|
@ -1,23 +0,0 @@
|
|||||||
--- #################### 注册中心相关配置 ####################
|
|
||||||
|
|
||||||
spring:
|
|
||||||
cloud:
|
|
||||||
nacos:
|
|
||||||
server-addr: 127.0.0.1:8848
|
|
||||||
discovery:
|
|
||||||
namespace: dev # 命名空间。这里使用 dev 开发环境
|
|
||||||
metadata:
|
|
||||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
|
||||||
|
|
||||||
--- #################### 配置中心相关配置 ####################
|
|
||||||
|
|
||||||
spring:
|
|
||||||
cloud:
|
|
||||||
nacos:
|
|
||||||
# Nacos Config 配置项,对应 NacosConfigProperties 配置属性类
|
|
||||||
config:
|
|
||||||
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
|
|
||||||
namespace: dev # 命名空间 dev 的ID,不能直接使用 dev 名称。创建命名空间的时候需要指定ID为 dev,这里使用 dev 开发环境
|
|
||||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
|
||||||
name: ${spring.application.name} # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
|
|
||||||
file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties
|
|
@ -1,76 +0,0 @@
|
|||||||
<configuration>
|
|
||||||
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
|
||||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
|
||||||
<!-- 变量 yudao.info.base-package,基础业务包 -->
|
|
||||||
<springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/>
|
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
|
||||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
|
||||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
|
||||||
</layout>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- 文件 Appender -->
|
|
||||||
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
|
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
|
||||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
|
||||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
|
||||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
|
||||||
</layout>
|
|
||||||
</encoder>
|
|
||||||
<!-- 日志文件名 -->
|
|
||||||
<file>${LOG_FILE}</file>
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
|
||||||
<!-- 滚动后的日志文件名 -->
|
|
||||||
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
|
|
||||||
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
|
|
||||||
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
|
|
||||||
<!-- 日志文件,到达多少容量,进行滚动 -->
|
|
||||||
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
|
|
||||||
<!-- 日志文件的总大小,0 表示不限制 -->
|
|
||||||
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
|
|
||||||
<!-- 日志文件的保留天数 -->
|
|
||||||
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
|
|
||||||
</rollingPolicy>
|
|
||||||
</appender>
|
|
||||||
<!-- 异步写入日志,提升性能 -->
|
|
||||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
|
||||||
<!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
|
|
||||||
<discardingThreshold>0</discardingThreshold>
|
|
||||||
<!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
|
|
||||||
<queueSize>256</queueSize>
|
|
||||||
<appender-ref ref="FILE"/>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- SkyWalking GRPC 日志收集,实现日志中心。注意:SkyWalking 8.4.0 版本开始支持 -->
|
|
||||||
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
|
|
||||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
|
||||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
|
||||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
|
||||||
</layout>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- 本地环境 -->
|
|
||||||
<springProfile name="local">
|
|
||||||
<root level="INFO">
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
|
||||||
</root>
|
|
||||||
</springProfile>
|
|
||||||
<!-- 其它环境 -->
|
|
||||||
<springProfile name="dev,test,stage,prod,default">
|
|
||||||
<root level="INFO">
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
<appender-ref ref="ASYNC"/>
|
|
||||||
<appender-ref ref="GRPC"/>
|
|
||||||
</root>
|
|
||||||
</springProfile>
|
|
||||||
|
|
||||||
</configuration>
|
|
@ -3,12 +3,12 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ludu-module-ticket-manager</artifactId>
|
<artifactId>ludu-module-ticketing</artifactId>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>ludu-module-ticket-manager-api</artifactId>
|
<artifactId>ludu-module-ticketing-api</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
@ -3,13 +3,13 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ludu-module-ticket-manager</artifactId>
|
<artifactId>ludu-module-ticketing</artifactId>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>ludu-module-ticket-manager-biz</artifactId>
|
<artifactId>ludu-module-ticketing-biz</artifactId>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<!-- 依赖服务 -->
|
<!-- 依赖服务 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
<artifactId>ludu-module-ticket-manager-api</artifactId>
|
<artifactId>ludu-module-ticketing-api</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Spring Cloud 基础 -->
|
<!-- Spring Cloud 基础 -->
|
@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class TicketManagerServerApplication {
|
public class TicketingServerApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(TicketManagerServerApplication.class, args);
|
SpringApplication.run(TicketingServerApplication.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -95,8 +95,7 @@ public class SaleDataServiceImpl implements SaleDataService {
|
|||||||
try {
|
try {
|
||||||
date1 = inputFormat.parse(startTime);
|
date1 = inputFormat.parse(startTime);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
// throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
System.out.println("抛出日期转换异常");
|
|
||||||
}
|
}
|
||||||
calendar.setTime(date1);
|
calendar.setTime(date1);
|
||||||
calendar.add(Calendar.DAY_OF_YEAR, -9);
|
calendar.add(Calendar.DAY_OF_YEAR, -9);
|
@ -40,7 +40,7 @@ spring:
|
|||||||
primary: master
|
primary: master
|
||||||
datasource:
|
datasource:
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://120.46.37.243:3306/ludu_ticket?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
url: jdbc:mysql://120.46.37.243:3306/ludu_ticketing?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
||||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
|
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
|
||||||
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
|
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
|
||||||
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
|
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user