springboot如何通過http動(dòng)態(tài)操作xxl-job任務(wù)
springboot通過http動(dòng)態(tài)操作xxl-job任務(wù)
一、maven依賴
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.4</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
二、配置文件
xxl:
job:
login:
address: http://192.168.31.91:18080/xxl-job-admin
username: admin
password: 123456
三、xxl-job實(shí)體類
XxlJobActuatorManagerInfo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxlJobActuatorManagerInfo {
private Integer recordsFiltered;
private Integer recordsTotal;
private List<XxlJobGroup> data;
}
XxlJobGroup
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxlJobGroup {
private int id;
private String appname;
private String title;
private int addressType; // 執(zhí)行器地址類型:0=自動(dòng)注冊(cè)、1=手動(dòng)錄入
private String addressList; // 執(zhí)行器地址列表,多地址逗號(hào)分隔(手動(dòng)錄入)
private Date updateTime;
// registry list
private List<String> registryList; // 執(zhí)行器地址列表(系統(tǒng)注冊(cè))
public List<String> getRegistryList() {
if (addressList!=null && addressList.trim().length()>0) {
registryList = new ArrayList<String>(Arrays.asList(addressList.split(",")));
}
return registryList;
}
}
XxlJobInfo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxlJobInfo {
private int id; // 主鍵ID
private int jobGroup; // 執(zhí)行器主鍵ID
private String jobDesc;
private String jobCron; //corn表達(dá)式
private Date addTime;
private Date updateTime;
private String author; // 負(fù)責(zé)人
private String alarmEmail; // 報(bào)警郵件
private String scheduleType; // 調(diào)度類型
private String scheduleConf; // 調(diào)度配置,值含義取決于調(diào)度類型
private String misfireStrategy; // 調(diào)度過期策略
private String executorRouteStrategy; // 執(zhí)行器路由策略
private String executorHandler; // 執(zhí)行器,任務(wù)Handler名稱
private String executorParam; // 執(zhí)行器,任務(wù)參數(shù)
private String executorBlockStrategy; // 阻塞處理策略
private int executorTimeout; // 任務(wù)執(zhí)行超時(shí)時(shí)間,單位秒
private int executorFailRetryCount; // 失敗重試次數(shù)
private String glueType; // GLUE類型 #com.xxl.job.core.glue.GlueTypeEnum
private String glueSource; // GLUE源代碼
private String glueRemark; // GLUE備注
private Date glueUpdatetime; // GLUE更新時(shí)間
private String childJobId; // 子任務(wù)ID,多個(gè)逗號(hào)分隔
private int triggerStatus; // 調(diào)度狀態(tài):0-停止,1-運(yùn)行
private long triggerLastTime; // 上次調(diào)度時(shí)間
private long triggerNextTime; // 下次調(diào)度時(shí)間
}
XxlJobResponseInfo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxlJobResponseInfo {
private Integer code;
private String msg;
private String content;
}
XxlJobTaskManagerInfo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxlJobTaskManagerInfo {
private Integer recordsFiltered;
private Integer recordsTotal;
private List<XxlJobInfo> data;
}
四、工具類
HttpClientConfig
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HttpClientConfig {
private String url;
private String username;
private String password;
private String oauthToken;
private int connectionTimeout = 60000;
private int requestTimeout = 60000;
private int webSocketPingInterval;
private int maxConcurrentRequestsPerHost = 30;
private int maxConnection = 40;
private String httpProxy;
private String httpsProxy;
private String proxyUsername;
private String proxyPassword;
private String userAgent;
private TlsVersion[] tlsVersions = new TlsVersion[]{TLS_1_2};
private String[] noProxy;
public static final String HTTP_PROTOCOL_PREFIX = "http://";
public static final String HTTPS_PROTOCOL_PREFIX = "https://";
}
HttpClientUtils
package com.mye.xxljobtest.util;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static okhttp3.ConnectionSpec.CLEARTEXT;
public class HttpClientUtils {
private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
/**
* json傳輸方式
*/
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static volatile OkHttpClient client;
public static Headers doLoginRequest(HttpClientConfig config, Map<String, String> params) {
try {
OkHttpClient client = getInstance(config);
FormBody.Builder builder = new FormBody.Builder();
for (Map.Entry<String, String> param : params.entrySet()) {
builder.add(param.getKey(), param.getValue());
}
FormBody formBody = builder.build();
Request request = new Request.Builder().url(config.getUrl()).post(formBody).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
System.out.println(JsonUtil.objectToJson(response));
return response.headers();
} else if (response.body() != null){
return null;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static String doFormRequest(HttpClientConfig config, Map<String, String> params, String cookie) {
try {
OkHttpClient client = getInstance(config);
FormBody.Builder builder = new FormBody.Builder();
for (Map.Entry<String, String> param : params.entrySet()) {
builder.add(param.getKey(), param.getValue());
}
FormBody formBody = builder.build();
Request request = new Request.Builder().url(config.getUrl()).header("Cookie", cookie).post(formBody).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
System.out.println(JsonUtil.objectToJson(response));
return response.body().string();
} else if (response.body() != null){
return response.body().string();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static String doRequest(HttpClientConfig config, HttpMethod method, Map<String, String> headers, String body) {
try {
OkHttpClient client = getInstance(config);
//創(chuàng)建請(qǐng)求
RequestBody requestBody = RequestBody.create(JSON, StringUtils.isEmpty(body) ? "" : body);
Request.Builder builder = new Request.Builder();
if (!CollectionUtils.isEmpty(headers)) {
logger.info("headers : " + headers);
builder.headers(Headers.of(headers));
}
Request request = builder.method(method.name(), requestBody).url(config.getUrl()).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
return response.body().string();
} else if (response.body() != null){
return response.body().string();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 雙重檢查單例
* @param config OkHttpClient配置
* @return okHttpClient
*/
public static OkHttpClient getInstance(HttpClientConfig config) {
if (client == null) {
synchronized (OkHttpClient.class) {
if (client == null) {
client = createHttpClient(config);
}
}
}
//拿到client之后把認(rèn)證信息重新加一遍
client.newBuilder().addInterceptor(chain -> {
Request request = chain.request();
if (StringUtils.hasText(config.getUsername()) && StringUtils.hasText(config.getPassword())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", Credentials.basic(config.getUsername(), config.getPassword())).build();
return chain.proceed(authReq);
} else if (StringUtils.hasText( config.getOauthToken())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", "Bearer " + config.getOauthToken()).build();
return chain.proceed(authReq);
}
return chain.proceed(request);
});
return client;
}
private static OkHttpClient createHttpClient(final HttpClientConfig config) {
try {
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.followRedirects(true);
httpClientBuilder.followSslRedirects(true);
if (config.getConnectionTimeout() > 0) {
httpClientBuilder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getRequestTimeout() > 0) {
httpClientBuilder.readTimeout(config.getRequestTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getWebSocketPingInterval() > 0) {
httpClientBuilder.pingInterval(config.getWebSocketPingInterval(), TimeUnit.MILLISECONDS);
}
if (config.getMaxConcurrentRequestsPerHost() > 0) {
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequestsPerHost(config.getMaxConcurrentRequestsPerHost());
httpClientBuilder.dispatcher(dispatcher);
}
if (config.getMaxConnection() > 0) {
ConnectionPool connectionPool = new ConnectionPool(config.getMaxConnection(), 60, TimeUnit.SECONDS);
httpClientBuilder.connectionPool(connectionPool);
}
// Only check proxy if it's a full URL with protocol
if (config.getUrl().toLowerCase().startsWith(HttpClientConfig.HTTP_PROTOCOL_PREFIX) || config.getUrl().startsWith(HttpClientConfig.HTTPS_PROTOCOL_PREFIX)) {
try {
URL proxyUrl = getProxyUrl(config);
if (proxyUrl != null) {
httpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyUrl.getHost(), proxyUrl.getPort())));
if (config.getProxyUsername() != null) {
httpClientBuilder.proxyAuthenticator((route, response) -> {
String credential = Credentials.basic(config.getProxyUsername(), config.getProxyPassword());
return response.request().newBuilder().header("Proxy-Authorization", credential).build();
});
}
}
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid proxy server configuration", e);
}
}
if (config.getUserAgent() != null && !config.getUserAgent().isEmpty()) {
httpClientBuilder.addNetworkInterceptor(chain -> {
Request agent = chain.request().newBuilder().header("User-Agent", config.getUserAgent()).build();
return chain.proceed(agent);
});
}
if (config.getTlsVersions() != null && config.getTlsVersions().length > 0) {
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(config.getTlsVersions())
.build();
httpClientBuilder.connectionSpecs(Arrays.asList(spec, CLEARTEXT));
}
return httpClientBuilder.build();
} catch (Exception e) {
throw new IllegalArgumentException("創(chuàng)建OKHTTPClient錯(cuò)誤", e);
}
}
private static URL getProxyUrl(HttpClientConfig config) throws MalformedURLException {
URL master = new URL(config.getUrl());
String host = master.getHost();
if (config.getNoProxy() != null) {
for (String noProxy : config.getNoProxy()) {
if (host.endsWith(noProxy)) {
return null;
}
}
}
String proxy = config.getHttpsProxy();
String http = "http";
if (http.equals(master.getProtocol())) {
proxy = config.getHttpProxy();
}
if (proxy != null) {
return new URL(proxy);
}
return null;
}
}
XxlJobApiUtils
package com.mye.xxljobtest.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.mye.xxljobtest.jobcore.*;
import okhttp3.Headers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* xxl-job api 操作工具類
* @author hl
* @date 2022/8/1 14:05
*/
@Component
public class XxlJobApiUtils {
private static final Logger logger = LoggerFactory.getLogger(XxlJobApiUtils.class);
@Value("${xxl.job.login.address}")
private String xxlJobLoginAddress;
@Value("${xxl.job.login.username}")
private String xxlJobLoginUserName;
@Value("${xxl.job.login.password}")
private String xxlJobLoginPassword;
/**
* 啟動(dòng)xxl-job任務(wù)管理
* @param taskId 任務(wù)管理id
*/
public void startTask(Integer taskId){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建參數(shù)
Map<String, String> form = new HashMap<>();
form.put("id", "" + taskId);
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/start");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
}
/**
* 刪除 xxl-job任務(wù)管理
* @param id 任務(wù)id
*/
public void deleteTask(Integer id){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建任務(wù)管理參數(shù)
Map<String, String> form = new HashMap<>();
form.put("id", id + "");
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/remove");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
}
/**
* 編輯 xxl-job任務(wù)管理
* @param xxlJobInfo 查詢參數(shù)
*/
public void editTask(XxlJobInfo xxlJobInfo){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建任務(wù)管理參數(shù)
Map<String, String> form = new HashMap<>();
form.put("id",xxlJobInfo.getId() + "");
//注意這里需要先創(chuàng)建執(zhí)行器,然后拿到執(zhí)行器的id賦值給JobGroup
form.put("jobGroup", xxlJobInfo.getJobGroup() + "");
form.put("jobDesc", xxlJobInfo.getJobDesc());
form.put("executorRouteStrategy", "ROUND");
form.put("jobCron", xxlJobInfo.getJobCorn());
form.put("glueType", "BEAN");
form.put("executorHandler", xxlJobInfo.getExecutorHandler());
form.put("executorBlockStrategy", "SERIAL_EXECUTION");
form.put("author", "mye");
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/update");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
}
/**
* 查詢所有的task
* @param xxlJobInfo
* @return
*/
public XxlJobTaskManagerInfo selectAllTask(XxlJobInfo xxlJobInfo) {
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建任務(wù)管理參數(shù)
Map<String, String> form = new HashMap<>();
form.put("jobGroup", xxlJobInfo.getJobGroup() + "");
form.put("triggerStatus", "-1");
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/pageList");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
return JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobTaskManagerInfo.class);
}
/**
* 查詢 xxl-job任務(wù)管理
* @param xxlJobInfo 查詢參數(shù)
*/
public XxlJobTaskManagerInfo selectTask(XxlJobInfo xxlJobInfo){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建任務(wù)管理參數(shù)
Map<String, String> form = new HashMap<>();
form.put("jobGroup", xxlJobInfo.getJobGroup() + "");
form.put("jobDesc", xxlJobInfo.getJobDesc());
form.put("executorHandler", xxlJobInfo.getExecutorHandler());
form.put("author", xxlJobInfo.getAuthor());
form.put("triggerStatus", "-1");
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/pageList");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobTaskManagerInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobTaskManagerInfo.class);
if (ObjectUtil.isNull(info) || CollectionUtil.isEmpty(info.getData())){
logger.error("xxl-job任務(wù)管理不存在",new RuntimeException());
}
return info;
}
/**
* 創(chuàng)建任務(wù)管理
* @param xxlJobInfo 創(chuàng)建參數(shù)
*/
public XxlJobResponseInfo createTask(XxlJobInfo xxlJobInfo){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建任務(wù)管理參數(shù)
Map<String, String> form = new HashMap<>();
form.put("jobGroup", xxlJobInfo.getJobGroup() + "");
form.put("jobDesc", xxlJobInfo.getJobDesc());
form.put("executorRouteStrategy", "ROUND");
form.put("jobCron", xxlJobInfo.getJobCorn());
form.put("glueType", "BEAN");
form.put("executorHandler", xxlJobInfo.getExecutorHandler());
form.put("executorBlockStrategy", "SERIAL_EXECUTION");
form.put("author", "mye");
//創(chuàng)建任務(wù)管理
clientConfig.setUrl(xxlJobLoginAddress + "/jobinfo/add");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
return info;
}
/**
* 刪除執(zhí)行器
*/
public void deleteActuator(XxlJobGroup xxlJobGroup) {
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建查詢執(zhí)行器管理器參數(shù)
Map<String, String> form = new HashMap<>();
form.put("id", xxlJobGroup.getId() + "");
//創(chuàng)建執(zhí)行器管理器地址
clientConfig.setUrl(xxlJobLoginAddress + "/jobgroup/remove");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()) {
logger.error(info.getMsg(), new RuntimeException());
}
}
/**
* 編輯執(zhí)行器
*/
public void editActuator(XxlJobGroup xxlJobGroup){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建查詢執(zhí)行器管理器參數(shù)
Map<String, String> form = new HashMap<>();
form.put("appname", xxlJobGroup.getAppname());
form.put("title", xxlJobGroup.getTitle());
form.put("addressType", xxlJobGroup.getAddressType() + "");
form.put("id", xxlJobGroup.getId() + "");
//創(chuàng)建執(zhí)行器管理器地址
clientConfig.setUrl(xxlJobLoginAddress + "/jobgroup/update");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
}
/**
* 查詢執(zhí)行器 (appname 和 title 都是模糊查詢)
* @param xxlJobGroup XxlJobGroup
* @return xxlJobGroup 集合
*/
public List<XxlJobGroup> selectActuator(XxlJobGroup xxlJobGroup){
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建查詢執(zhí)行器管理器參數(shù)
Map<String, String> form = new HashMap<>();
form.put("appname", xxlJobGroup.getAppname());
form.put("title", xxlJobGroup.getTitle());
//創(chuàng)建執(zhí)行器管理器地址
clientConfig.setUrl(xxlJobLoginAddress + "/jobgroup/pageList");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobActuatorManagerInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobActuatorManagerInfo.class);
if (CollectionUtil.isEmpty(info.getData())){
throw new RuntimeException("該執(zhí)行器管理器不存在:" + xxlJobGroup.getAppname());
}
return info.getData();
}
/**
* 創(chuàng)建執(zhí)行器
*
* @param xxlJobGroup 創(chuàng)建參數(shù)
*/
public XxlJobResponseInfo createActuator(XxlJobGroup xxlJobGroup) {
//獲取登錄cookie
HttpClientConfig clientConfig = new HttpClientConfig();
String cookie = loginTaskCenter(clientConfig);
//創(chuàng)建執(zhí)行器管理器參數(shù)
Map<String, String> form = new HashMap<>();
form.put("appname", xxlJobGroup.getAppname());
form.put("title", xxlJobGroup.getTitle());
form.put("addressType", xxlJobGroup.getAddressType() + "");
//創(chuàng)建執(zhí)行器管理器地址
clientConfig.setUrl(xxlJobLoginAddress + "/jobgroup/save");
String result = HttpClientUtils.doFormRequest(clientConfig, form, cookie);
XxlJobResponseInfo info = JSONUtil.toBean(JSONUtil.parseObj(result), XxlJobResponseInfo.class);
if (ObjectUtil.isNull(info) || info.getCode() != HttpStatus.OK.value()){
logger.error(info.getMsg(),new RuntimeException());
}
return info;
}
/**
* 登錄任務(wù)調(diào)度平臺(tái)
*
* @param clientConfig clientConfig
* @return cookie
*/
public String loginTaskCenter(HttpClientConfig clientConfig) {
Map<String, String> loginForm = new HashMap<>();
clientConfig.setUrl(xxlJobLoginAddress + "/login");
clientConfig.setUsername(xxlJobLoginUserName);
clientConfig.setPassword(xxlJobLoginPassword);
loginForm.put("userName", xxlJobLoginUserName);
loginForm.put("password", xxlJobLoginPassword);
Headers headers = HttpClientUtils.doLoginRequest(clientConfig, loginForm);
assert headers != null;
return headers.get("Set-Cookie");
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot Actuator未授權(quán)訪問漏洞的排查和解決方法
Spring Boot Actuator 是開發(fā)和管理生產(chǎn)級(jí) Spring Boot 應(yīng)用程序的重要工具,它可以幫助你確保應(yīng)用程序的穩(wěn)定性和性能,本文給大家介紹了SpringBoot Actuator未授權(quán)訪問漏洞的排查和解決方法,需要的朋友可以參考下2024-05-05
Windows10系統(tǒng)下JDK1.8的下載安裝及環(huán)境變量配置的教程
這篇文章主要介紹了Windows10系統(tǒng)下JDK1.8的下載安裝及環(huán)境變量配置的教程,本文圖文并茂給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Java實(shí)現(xiàn)企業(yè)員工管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)企業(yè)員工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Springboot+Redis實(shí)現(xiàn)API接口防刷限流的項(xiàng)目實(shí)踐
本文主要介紹了Springboot+Redis實(shí)現(xiàn)API接口防刷限流的項(xiàng)目實(shí)踐,通過限流可以讓系統(tǒng)維持在一個(gè)相對(duì)穩(wěn)定的狀態(tài),為更多的客戶提供服務(wù),具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07
Spring MVC溫故而知新系列教程之請(qǐng)求映射RequestMapping注解
這篇文章主要介紹了Spring MVC溫故而知新系列教程之請(qǐng)求映射RequestMapping注解的相關(guān)知識(shí),文中給大家介紹了RequestMapping注解提供的幾個(gè)屬性及注解說明,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05
IDEA設(shè)置生成帶注釋的getter和setter的圖文教程
通常我們用idea默認(rèn)生成的getter和setter方法是不帶注釋的,當(dāng)然,我們同樣可以設(shè)置idea像MyEclipse一樣生成帶有Javadoc的模板,具體設(shè)置方法,大家參考下本文2018-05-05
java 對(duì)文件夾目錄進(jìn)行深度遍歷實(shí)例代碼
這篇文章主要介紹了java 對(duì)文件夾目錄進(jìn)行深度遍歷實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03

