项目中需要后端以 无入侵
的方式,调用调度中心API服务。然而调度中心设置了登录,调度中心API接口对cookie进行了验证,feign访问调度中心API服务时,需通过其登录验证。
通过FeignClient客户端声明式调用调度中心Api服务与普通FeignClient相比作了一下几点处理:
image.png
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.3.0</version></dependency>2.HttpResultForXxlJob.java
import com.alibaba.fastjson.JSON;import lombok.Data;import java.io.Serializable;/** * xxl-job Api接口响应包装类
*
* @author liudong
* @date 2021/4/25 16:37
*/
@Data
public class HttpResultForXxlJob<T> implements Serializable { private static final long serialVersionUID = 6512789515344894483L; /** * 请求状态码
*/
private int code;
/**
* 消息
*/
private String msg;
/**
* 返回数据信息
*/
private T content; /** * 序列化为Json
*
* @return json字符串
*/
@Override
public String toString() {
return JSON.toJSONString(this);
}}import com.alibaba.fastjson.JSONObject;import com.gaodun.pms.cdp.common.dto.external.xxljob.HttpResultForXxlJob;import feign.Response;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.*;import java.util.Map;/** * xxl-job客户端
*
* @author liudong
* @date 2021/4/25 16:33
*/
@FeignClient(name = "xxlJobClient", url = "${third-party.config.xxl-job.host:not found xxl-job service url}")
public interface XxlJobClient {
/**
* xxl-job登录接口
*
* @param params 参数
* @return 响应信息
*/
@PostMapping(value = "/xxl-job-admin/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
Response login(@RequestBody Map<String, ?> params);
/** * 创建定时任务
*
* @param cookie cookie
* @param params 定时任务参数
* @return 定时任务ID
*/
@PostMapping(value = "/xxl-job-admin/jobinfo/add", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
HttpResultForXxlJob<Integer> add(@RequestHeader("Cookie") String cookie, @RequestBody Map<String, ?> params);
/** * 更新定时任务
*
* @param cookie cookie
* @param params 定时任务更新参数
* @return 执行结果
*/
@PutMapping(value = "/xxl-job-admin/jobinfo/update", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
HttpResultForXxlJob<String> update(@RequestHeader("Cookie") String cookie, @RequestBody Map<String, ?> params);
/** * 删除定时任务
*
* @param cookie cookie
* @param id 定时任务更新参数
* @return 执行结果
*/
@DeleteMapping(value = "/xxl-job-admin/jobinfo/remove")
HttpResultForXxlJob<String> remove(@RequestHeader("Cookie") String cookie, @RequestParam("id") int id);
/** * 开启任务
*
* @param cookie cookie
* @param id 定时任务ID
* @return 执行结果
*/
@PutMapping(value = "/xxl-job-admin/jobinfo/start")
HttpResultForXxlJob<String> start(@RequestHeader("Cookie") String cookie, @RequestParam("id") int id);
/** * 结束任务
*
* @param cookie cookie
* @param id 定时任务ID
* @return 执行结果
*/
@PutMapping(value = "/xxl-job-admin/jobinfo/stop")
HttpResultForXxlJob<String> stop(@RequestHeader("Cookie") String cookie, @RequestParam("id") int id);
/** * 结束任务
*
* @param cookie cookie
* @param params 查询参数
* @return 执行结果
*/
@GetMapping(value = "/xxl-job-admin/joblog/pageList")
JSONObject log(@RequestHeader("Cookie") String cookie, @RequestParam("params") Map<String, Object> params);
}import cn.hutool.core.bean.BeanUtil;import cn.hutool.core.map.MapUtil;import cn.hutool.http.HttpStatus;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.gaodun.pms.cdp.common.constant.CacheConstant;import com.gaodun.pms.cdp.common.constant.XxlJobConstant;import com.gaodun.pms.cdp.common.dto.external.xxljob.HttpResultForXxlJob;import com.gaodun.pms.cdp.common.dto.xxljob.XxlJobLogDTO;import com.gaodun.pms.cdp.common.exception.ErrorCode;import com.gaodun.pms.cdp.common.request.xxljob.AddOrUpdateXxlJobInfoRequest;import com.gaodun.pms.cdp.service.acm.ApplicationConfig;import com.gaodun.pms.cdp.service.acm.JobConfig;import com.gaodun.pms.cdp.service.external.feign.XxlJobClient;import com.gaodunwangxiao.pms.exception.AbstractAssert;import com.gaodunwangxiao.pms.exception.ExceptionFactory;import com.gaodunwangxiao.pms.exception.SystemException;import feign.FeignException;import feign.Response;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.ObjectUtils;import org.assertj.core.util.Lists;import org.springframework.beans.factory.annotation.Value;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.retry.annotation.Backoff;import org.springframework.retry.annotation.Recover;import org.springframework.retry.annotation.Retryable;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.TimeUnit;/** * 任务管理处理器
*
* @author liudong
* @date 2021/4/25 10:56
*/
@Slf4j
@Component
public class XxlJobComponent {
/** * xxl job 账号
*/
@Value("${xxl.job.user-name}")
private String userName;
/** * xxl job 密码
*/
@Value("${xxl.job.password}")
private String password;
/** * xxl-job客户端
*/
@Resource
private XxlJobClient xxlJobClient;
/** * 应用全局配置
*/
@Resource
private ApplicationConfig applicationConfig;
/**
* redis操作类
*/
@Resource
private RedisTemplate<String, Object> redisTemplate;
/** * 登录xxl-job
*/
public void login() {
Map<String, Object> userInfo = new HashMap<>(MapUtil.DEFAULT_INITIAL_CAPACITY);
userInfo.put("userName", userName);
userInfo.put("password", password);
// 设置cookie永久有效,对应xxl-job记住密码
userInfo.put("ifRemember", "on");
Response response = xxlJobClient.login(userInfo);
if (HttpStatus.HTTP_OK == response.status()) {
response.headers().get(XxlJobConstant.COOKIE_KEY).forEach(e -> {
if (e.contains(XxlJobConstant.XXL_JOB_LOGIN_IDENTITY)) {
redisTemplate.opsForValue().set(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY, e, CacheConstant.XXL_JOB_COOKIE_REDIS_TIMEOUT, TimeUnit.HOURS);
}
});
} else {
throw ExceptionFactory.systemException(ErrorCode.LOGIN_XXL_JOB_FAILURE_EXCEPTION);
}
}
/** * 创建任务
*
* @param addOrUpdateXxlJobInfoRequest 任务参数
* @return 任务ID
*/
public Integer add(AddOrUpdateXxlJobInfoRequest addOrUpdateXxlJobInfoRequest) { if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) { login(); } if (ObjectUtils.isNotEmpty(addOrUpdateXxlJobInfoRequest)) { HttpResultForXxlJob result = xxlJobClient.add(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), BeanUtil.beanToMap(addOrUpdateXxlJobInfoRequest)); if (HttpStatus.HTTP_OK == result.getCode()) { log.info(result.getMsg()); return (int) result.getContent(); } } return null; } /** * 更新任务
*
* @param addOrUpdateXxlJobInfoRequest 任务参数
*/
public void update(AddOrUpdateXxlJobInfoRequest addOrUpdateXxlJobInfoRequest) {
if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) {
login();
}
if (ObjectUtils.isNotEmpty(addOrUpdateXxlJobInfoRequest)) {
HttpResultForXxlJob result = xxlJobClient.update(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), BeanUtil.beanToMap(addOrUpdateXxlJobInfoRequest));
log.info(result.getMsg());
AbstractAssert.isTrue(HttpStatus.HTTP_OK == result.getCode(), ErrorCode.UPDATE_JOB_FAILURE_EXCEPTION);
}
}
/** * 删除任务
*
* @param id 任务ID
*/
public void remove(Integer id) {
if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) {
login();
}
if (ObjectUtils.isNotEmpty(id)) {
HttpResultForXxlJob result = xxlJobClient.remove(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), id);
log.info(result.getMsg());
AbstractAssert.isTrue(HttpStatus.HTTP_OK == result.getCode(), ErrorCode.REMOVE_JOB_FAILURE_EXCEPTION);
}
}
/** * 启动任务
*
* @param id 任务ID
*/
public void start(Integer id) {
if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) {
login();
}
if (ObjectUtils.isNotEmpty(id)) {
HttpResultForXxlJob result = xxlJobClient.start(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), id);
log.info(result.getMsg());
AbstractAssert.isTrue(HttpStatus.HTTP_OK == result.getCode(), ErrorCode.START_JOB_FAILURE_EXCEPTION);
}
}
/** * 停止任务
*
* @param id 任务ID
*/
public void stop(Integer id) {
if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) {
login();
}
if (ObjectUtils.isNotEmpty(id)) {
HttpResultForXxlJob result = xxlJobClient.stop(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), id);
log.info(result.getMsg());
AbstractAssert.isTrue(HttpStatus.HTTP_OK == result.getCode(), ErrorCode.STOP_JOB_FAILURE_EXCEPTION);
}
}
/** * 查询日志
*
* @param params 查询参数
* @return 结果集
*/
@Retryable(value = SystemException.class, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
public List<XxlJobLogDTO> log(Map<String, Object> params) {
try {
if (Boolean.FALSE.equals(redisTemplate.hasKey(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY))) {
login();
}
if (ObjectUtils.isEmpty(params)) {
return Lists.newArrayList();
}
JSONObject result = xxlJobClient.log(String.valueOf(redisTemplate.opsForValue().get(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY)), params);
if (ObjectUtils.isNotEmpty(result) && ObjectUtils.isNotEmpty(result.getString("data"))) {
return JSON.parseArray(result.getString("data"), XxlJobLogDTO.class);
}
} catch (FeignException e) { redisTemplate.delete(CacheConstant.XXL_JOB_COOKIE_REDIS_KEY); throw ExceptionFactory.systemException("远程操作xxl-job失败,进行重试!", e); } return Lists.newArrayList(); } /** * 重试次数达到最大后回调处理
*
* @param systemException 重试异常
*/
@Recover
public void recoverCallback(SystemException systemException) {
log.error("远程操作xxl-job异常!", systemException);
}
}import cn.hutool.core.bean.BeanUtil;import com.gaodun.pms.cdp.common.dto.xxljob.XxlJobInfoDTO;import com.gaodun.pms.cdp.common.enums.MisfireStrategyEnum;import com.gaodun.pms.cdp.common.request.xxljob.AddOrUpdateXxlJobInfoRequest;import com.gaodun.pms.cdp.web.CdpApplication;import feign.Response;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.BeanUtils;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import javax.annotation.Resource;import java.util.HashMap;import java.util.Map;/** * xxl-job api Test
*
* @author liudong
* @date 2021/4/26 9:45
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CdpApplication.class)
public class XxlJobClientTest { @Resource private XxlJobClient xxlJobClient; @Test public void login() { } @Test public void add() { Map<String, Object> hashMap = new HashMap(2); hashMap.put("userName", "admin"); hashMap.put("password", "123456"); Response response = xxlJobClient.login(hashMap); AddOrUpdateXxlJobInfoRequest addOrUpdateXxlJobInfoRequest = new AddOrUpdateXxlJobInfoRequest(); addOrUpdateXxlJobInfoRequest.setJobGroup(2); addOrUpdateXxlJobInfoRequest.setJobDesc("test"); addOrUpdateXxlJobInfoRequest.setAuthor("liudong"); addOrUpdateXxlJobInfoRequest.setAlarmEmail(""); addOrUpdateXxlJobInfoRequest.setScheduleType("CRON"); addOrUpdateXxlJobInfoRequest.setScheduleConf("0/6 * * * * ?"); addOrUpdateXxlJobInfoRequest.setGlueType("BEAN"); addOrUpdateXxlJobInfoRequest.setExecutorHandler("testHandler"); addOrUpdateXxlJobInfoRequest.setExecutorRouteStrategy("FIRST"); addOrUpdateXxlJobInfoRequest.setMisfireStrategy(MisfireStrategyEnum.DO_NOTHING.toString()); addOrUpdateXxlJobInfoRequest.setExecutorBlockStrategy("SERIAL_EXECUTION"); XxlJobInfoDTO xxlJobInfoDTO = new XxlJobInfoDTO(); BeanUtils.copyProperties(addOrUpdateXxlJobInfoRequest, xxlJobInfoDTO); Map<String, Object> stringObjectMap = BeanUtil.beanToMap(addOrUpdateXxlJobInfoRequest); response.headers().get("set-cookie").forEach(e -> { if (e.contains("XXL_JOB_LOGIN_IDENTITY")) { System.out.println(xxlJobClient.add(e, stringObjectMap).toString()); } }); } @Test public void update() { Map<String, Object> hashMap = new HashMap(2); hashMap.put("userName", "admin"); hashMap.put("password", "123456"); Response response = xxlJobClient.login(hashMap); AddOrUpdateXxlJobInfoRequest addOrUpdateXxlJobInfoRequest = new AddOrUpdateXxlJobInfoRequest(); addOrUpdateXxlJobInfoRequest.setId(14); addOrUpdateXxlJobInfoRequest.setJobGroup(2); addOrUpdateXxlJobInfoRequest.setJobDesc("update"); addOrUpdateXxlJobInfoRequest.setAuthor("liudong"); addOrUpdateXxlJobInfoRequest.setAlarmEmail(""); addOrUpdateXxlJobInfoRequest.setScheduleType("CRON"); addOrUpdateXxlJobInfoRequest.setScheduleConf("0/6 * * * * ?"); addOrUpdateXxlJobInfoRequest.setGlueType("BEAN"); addOrUpdateXxlJobInfoRequest.setExecutorHandler("testHandler"); addOrUpdateXxlJobInfoRequest.setExecutorRouteStrategy("FIRST"); addOrUpdateXxlJobInfoRequest.setMisfireStrategy(MisfireStrategyEnum.DO_NOTHING.toString()); addOrUpdateXxlJobInfoRequest.setExecutorBlockStrategy("SERIAL_EXECUTION"); XxlJobInfoDTO xxlJobInfoDTO = new XxlJobInfoDTO(); BeanUtils.copyProperties(addOrUpdateXxlJobInfoRequest, xxlJobInfoDTO); Map<String, Object> stringObjectMap = BeanUtil.beanToMap(addOrUpdateXxlJobInfoRequest); response.headers().get("set-cookie").forEach(e -> { if (e.contains("XXL_JOB_LOGIN_IDENTITY")) { System.out.println(xxlJobClient.update(e, stringObjectMap).toString()); } }); } @Test public void remove() { Map<String, Object> hashMap = new HashMap(2); hashMap.put("userName", "admin"); hashMap.put("password", "123456"); Response response = xxlJobClient.login(hashMap); response.headers().get("set-cookie").forEach(e -> { if (e.contains("XXL_JOB_LOGIN_IDENTITY")) { System.out.println(xxlJobClient.remove(e, 23).toString()); } }); } @Test public void start() { Map<String, Object> hashMap = new HashMap(2); hashMap.put("userName", "admin"); hashMap.put("password", "123456"); Response response = xxlJobClient.login(hashMap); response.headers().get("set-cookie").forEach(e -> { if (e.contains("XXL_JOB_LOGIN_IDENTITY")) { System.out.println(xxlJobClient.start(e, 22).toString()); } }); } @Test public void stop() { Map<String, Object> hashMap = new HashMap(2); hashMap.put("userName", "admin"); hashMap.put("password", "123456"); Response response = xxlJobClient.login(hashMap); response.headers().get("set-cookie").forEach(e -> { if (e.contains("XXL_JOB_LOGIN_IDENTITY")) { System.out.println(xxlJobClient.stop(e, 22).toString()); } }); }}原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。