ruoyi-cloud登錄接口實現滑塊驗證碼

一、前言

ruoyi項目默認的驗證碼是這樣的
在這里插入圖片描述

今天來嘗試增加滑塊驗證碼,我們用到的是tianai-captcha
文檔地址:http://doc.captcha.tianai.cloud/
源碼地址:https://gitee.com/tianai/tianai-captcha

下面來看具體的步驟。

二、后端

gateway中引入依賴

<dependency><groupId>cloud.tianai.captcha</groupId><artifactId>tianai-captcha-springboot-starter</artifactId><version>1.4.1</version>
</dependency>

并增加相應的配置

# 客戶端驗證碼
captcha:cache:enabled: truecache-size: 20# 二次驗證secondary:enabled: false# 是否初始化默認資源init-default-resource: false

gateway中新增加一個SliderCaptchaHandler處理類

import cloud.tianai.captcha.spring.application.ImageCaptchaApplication;
import cloud.tianai.captcha.spring.vo.CaptchaResponse;
import cloud.tianai.captcha.spring.vo.ImageCaptchaVO;
import com.iinplus.common.core.exception.CaptchaException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;import javax.annotation.Resource;/*** 驗證碼獲取*/
@Component
public class SliderCaptchaHandler implements HandlerFunction<ServerResponse> {@Resourceprivate ImageCaptchaApplication sca;@Overridepublic Mono<ServerResponse> handle(ServerRequest serverRequest) {CaptchaResponse<ImageCaptchaVO> res;try {// 1.生成滑塊驗證碼(該數據返回給前端用于展示驗證碼數據)res = sca.generateCaptcha();} catch (CaptchaException e) {return Mono.error(e);}return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(res));}
}

RouterFunctionConfiguration中新增一個路由

@Resource
private SliderCaptchaHandler sliderCaptchaHandler;@Bean
public RouterFunction routerFunc() {return RouterFunctions.route(RequestPredicates.GET("/captcha").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),            sliderCaptchaHandler);
}

新增一個filter類,用來驗證圖形驗證碼。

import cloud.tianai.captcha.common.response.ApiResponse;
import cloud.tianai.captcha.spring.application.ImageCaptchaApplication;
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.iinplus.common.core.exception.CaptchaException;
import com.iinplus.common.core.utils.ServletUtils;
import com.iinplus.common.core.utils.StringUtils;
import com.iinplus.gateway.config.properties.CaptchaProperties;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;import javax.annotation.Resource;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;/*** 驗證碼過濾器*/
@Component
public class ValidateCaptchaFilter extends AbstractGatewayFilterFactory<Object> {private final static String[] VALIDATE_URL = new String[]{"/system/login"};@Resourceprivate ImageCaptchaApplication sca;@Resourceprivate CaptchaProperties captchaProperties;private static final String TRACK = "sliderCaptchaTrack";private static final String UUID = "id";@Overridepublic GatewayFilter apply(Object config) {return (exchange, chain) -> {ServerHttpRequest request = exchange.getRequest();// 非登錄/注冊請求或驗證碼關閉,不處理List<String> list = Arrays.asList(VALIDATE_URL);// 請求地址String url = request.getURI().getPath();if (!StringUtils.matches(url, list) || !captchaProperties.getEnabled()) {return chain.filter(exchange);}try {String rspStr = resolveBodyFromRequest(request);if (StringUtils.isEmpty(rspStr)) {throw new CaptchaException("驗證碼不能為空");}JSONObject obj = JSON.parseObject(rspStr);if (!obj.containsKey(UUID) || !obj.containsKey(TRACK)) {throw new CaptchaException("驗證碼不能為空");}String id = obj.getString(UUID);ImageCaptchaTrack sliderCaptchaTrack = obj.getObject(TRACK, ImageCaptchaTrack.class);ApiResponse<?> match = sca.matching(id, sliderCaptchaTrack);if (!match.isSuccess()) {throw new CaptchaException(match.getMsg());}} catch (Exception e) {e.printStackTrace();return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());}return chain.filter(exchange);};}private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {// 獲取請求體Flux<DataBuffer> body = serverHttpRequest.getBody();AtomicReference<String> bodyRef = new AtomicReference<>();body.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());DataBufferUtils.release(buffer);bodyRef.set(charBuffer.toString());});return bodyRef.get();}
}

注意:其中/system/login為登錄驗證的路徑,需要在網關中配置,并且需要加入白名單。

如果需要修改圖形驗證碼默認的背景圖

import cloud.tianai.captcha.common.constant.CaptchaTypeConstant;
import cloud.tianai.captcha.generator.common.constant.SliderCaptchaConstant;
import cloud.tianai.captcha.resource.common.model.dto.Resource;
import cloud.tianai.captcha.resource.common.model.dto.ResourceMap;
import cloud.tianai.captcha.resource.impl.DefaultResourceStore;
import cloud.tianai.captcha.resource.impl.provider.ClassPathResourceProvider;
import org.springframework.stereotype.Component;import static cloud.tianai.captcha.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH;/*** 自定義背景圖片*/
@Component
public class ResourceStore extends DefaultResourceStore {public ResourceStore() {// 滑塊驗證碼 模板 (系統內置)ResourceMap template1 = new ResourceMap("default", 4);template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));ResourceMap template2 = new ResourceMap("default", 4);template2.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));template2.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));// 1. 添加一些模板addTemplate(CaptchaTypeConstant.SLIDER, template1);addTemplate(CaptchaTypeConstant.SLIDER, template2);// 2. 添加自定義背景圖片addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/1.png", "default"));addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/2.png", "default"));addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/3.png", "default"));addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/4.png", "default"));addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/5.png", "default"));addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bg/6.png", "default"));}
}

圖片的路徑如下
在這里插入圖片描述

網關配置增加filters,把ValidateCaptchaFilter加上才生效

spring:cloud:gateway:discovery:... ...routes:# 系統模塊- id: systemuri: lb://systempredicates:- Path=/system/**filters:# 驗證碼處理- ValidateCaptchaFilter- StripPrefix=1

system模塊的登錄驗證

/*** 系統用戶登錄*/
@RestController
public class TokenController {@Autowiredprivate SysLoginService sysLoginService;@PostMapping("login")public RpcResult<?> login(@RequestBody @Validated LoginBody form) {   LoginUser userInfo = sysLoginService.login(form);... ...return RpcResult.success(rspMap);}
}
import lombok.Data;
import javax.validation.constraints.NotBlank;@Data
public class LoginBody {@NotBlank(message = "用戶名不能為空")private String username;@NotBlank(message = "密碼不能為空")private String password;
}

三、前端

components下增加一個組件SliderCaptcha

<template><div class="slider rotate"><div class="content"><div class="bg-img-div"><img :src="captcha.backgroundImage" id="imgId" alt/><canvas id="canvasId" ref="canvas"></canvas></div><div class="rotate-img-div" :style="rotateImgDiv"><img :src="captcha.templateImage" alt/></div></div><div class="slider-move"><div class="slider-move-track">拖動滑塊到正確位置</div><div class="slider-move-btn" :style="sliderMoveBtn" @mousedown="down" @touchstart="down"></div></div><div class="bottom"><div class="close-btn" @click="close()"></div><div class="refresh-btn" @click="refreshCaptcha"></div></div></div>
</template><script>
export default {name: "Slider",props: {captcha: {type: Object},},data() {return {currentCaptchaConfig: {},sliderMoveBtn: "",rotateImgDiv: "",checkParam: {}}},mounted() {this.initCaptcha();},methods: {refreshCaptcha() {this.$emit("init");this.initCaptcha();},initCaptcha() {this.sliderMoveBtn = "background-position: -5px 11.79625%; transform: translate(0, 0)";this.rotateImgDiv = "transform: translate(0, 0)";this.currentCaptchaConfig = {};let bgImageWidth = this.$refs.canvas.offsetWidth;let bgImageHeight = this.$refs.canvas.offsetHeight;this.checkParam = {bgImageWidth: bgImageWidth,bgImageHeight: bgImageHeight,startSlidingTime: new Date(),endSlidingTime: undefined,trackList: [],}},down(event) {let targetTouches = event.originalEvent ? event.originalEvent.targetTouches : event.targetTouches;let startX = event.pageX;let startY = event.pageY;if (startX === undefined) {startX = Math.round(targetTouches[0].pageX);startY = Math.round(targetTouches[0].pageY);}this.currentCaptchaConfig.startX = startX;this.currentCaptchaConfig.startY = startY;const pageX = this.currentCaptchaConfig.startX;const pageY = this.currentCaptchaConfig.startY;const startSlidingTime = this.checkParam.startSlidingTime;const trackList = this.checkParam.trackList;trackList.push({x: pageX - startX,y: pageY - startY,type: "down",t: (new Date().getTime() - startSlidingTime.getTime())});// pcwindow.addEventListener("mousemove", this.move);window.addEventListener("mouseup", this.up);// 手機端window.addEventListener("touchmove", this.move, false);window.addEventListener("touchend", this.up, false);this.sliderMoveBtn = `background-position:-5px 31.0092%`;},move(event) {if (event instanceof TouchEvent) {event = event.touches[0];}let pageX = Math.round(event.pageX);let pageY = Math.round(event.pageY);const startX = this.currentCaptchaConfig.startX;const startY = this.currentCaptchaConfig.startY;const startSlidingTime = this.checkParam.startSlidingTime;const end = 305;const trackList = this.checkParam.trackList;let moveX = pageX - startX;const track = {x: pageX - startX,y: pageY - startY,type: "move",t: (new Date().getTime() - startSlidingTime.getTime())};trackList.push(track);if (moveX < 0) {moveX = 0;} else if (moveX > end + 5) {moveX = end;}this.sliderMoveBtn = `transform:translate(${moveX}px, 0)`;this.rotateImgDiv = `transform:translate(${moveX}px, 0);`;},up(event) {window.removeEventListener("mousemove", this.move);window.removeEventListener("mouseup", this.up);// 手機端window.removeEventListener("touchmove", this.move);window.removeEventListener("touchend", this.up);if (event instanceof TouchEvent) {event = event.changedTouches[0];}let pageX = Math.round(event.pageX);let pageY = Math.round(event.pageY);const startX = this.currentCaptchaConfig.startX;const startY = this.currentCaptchaConfig.startY;const startSlidingTime = this.checkParam.startSlidingTime;const trackList = this.checkParam.trackList;const track = {x: pageX - startX,y: pageY - startY,type: "up",t: (new Date().getTime() - startSlidingTime.getTime())}trackList.push(track);this.checkParam.endSlidingTime = new Date();// 校驗this.checkCaptcha()},close() {this.$emit("close");},checkCaptcha() {//this.checkParam = {};this.$emit("checkParam", this.checkParam)this.$emit("login");}},
}
</script>
<style scoped>
.slider {background-color: #fff;width: 380px;height: 340px;z-index: 999;box-sizing: border-box;padding: 9px;border-radius: 6px;box-shadow: 0 0 11px 0 #999999;
}.slider .content {width: 100%;height: 160px;position: relative;
}.bg-img-div {width: 100%;height: 100%;position: absolute;transform: translate(0px, 0px);
}.bg-img-div img {width: 100%;
}.bg-img-div canvas {width: 100%;position: absolute;left: 0;top: 0;
}.slider .slider-move {height: 60px;width: 100%;margin: 0;position: relative;top: 80px
}.slider .bottom {height: 25px;width: 100%;margin: 65px 10px 10px 0;
}.refresh-btn, .close-btn, .slider-move-btn {background: url(../../assets/images/sprite.1.2.4.png) no-repeat;
}.refresh-btn, .close-btn {display: inline-block;
}.slider-move .slider-move-track {line-height: 38px;font-size: 14px;text-align: center;white-space: nowrap;color: #88949d;-moz-user-select: none;-webkit-user-select: none;user-select: none;border-radius: 50px;background: #dfe1e2;width: 100%;
}.slider {user-select: none;
}.slider-move .slider-move-btn {transform: translate(0, 0);background-position: -5px 11.79625%;position: absolute;top: -12px;left: 0;width: 100%;height: 100%;
}.slider-move-btn:hover, .close-btn:hover, .refresh-btn:hover {cursor: pointer
}.bottom .close-btn {width: 25px;height: 25px;background-position: 0 44.86874%;margin: 10px 10px 10px 5px;float: left;
}.bottom .refresh-btn {width: 25px;height: 25px;background-position: 0 81.38425%;margin: 7px 10px 10px 2px;float: left;
}.rotate-img-div {height: 140%;position: absolute;transform: translate(0, 0);
}.rotate-img-div img {height: 100%;
}
</style>

修改登錄和獲取驗證碼的方法

// 登錄方法
export function login(data) {return request({url: '/system/login',headers: {isToken: false},method: 'post',data: data})
}
// 獲取驗證碼
export function captcha() {return request({url: '/captcha',headers: {isToken: false},method: 'get',timeout: 20000})
}

修改login.vue頁面

<template><div class="login"><el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"><h3 class="title">xxxx管理系統</h3><el-form-item prop="username"><el-inputv-model="loginForm.username"type="text"auto-complete="off"placeholder="賬號"><svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /></el-input></el-form-item><el-form-item prop="password"><el-inputv-model="loginForm.password"type="password"auto-complete="off"placeholder="密碼"><svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /></el-input></el-form-item><!--注釋掉原來的驗證碼--><!--<el-form-item prop="code" v-if="captchaEnabled" style="margin: 10px 0"><el-inputv-model="loginForm.code"auto-complete="off"placeholder="驗證碼"style="width: 68%"@keyup.enter.native="handleLogin"><svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /></el-input><div class="login-code"><img :src="codeUrl" @click="getCode" class="login-code-img"/></div></el-form-item>--><el-form-item style="width:100%; margin: 10px 0"><el-checkbox v-model="loginForm.rememberMe">記住密碼</el-checkbox></el-form-item><el-form-item style="width:100%;margin-bottom: 10px"><el-button:loading="loading"size="medium"type="primary"style="width:100%;"@click.native.prevent="initCaptcha"><span v-if="!loading">登 錄</span><span v-else>登 錄 中...</span></el-button></el-form-item></el-form><!-- 滑塊驗證碼,通過show來控制顯示遮蔽層--><div v-if="show" class="mask"><SliderCaptchav-if="captchaVisible"ref="sliderCaptcha":captcha="captcha"@init="initCaptcha"@close="hideCaptcha"@login="handleLogin"/></div><!--  底部  --><div class="el-login-footer"><span>Copyright ? xxx All Rights Reserved.</span></div></div>
</template><script>
import {captcha} from '@/api/login'
import Cookies from "js-cookie";
import {decrypt, encrypt} from '@/utils/jsencrypt'
import SliderCaptcha from '@/components/SliderCaptcha'export default {name: "Login",components: {SliderCaptcha},data() {return {// codeUrl: "",show: false,captcha: {},captchaVisible: false,loginForm: {username: undefined,password: undefined,rememberMe: false,//code: "",//uuid: "",// 增加下面兩個屬性ImageCaptchaTrack: {},id: ''},loginRules: {username: [{ required: true, trigger: "blur", message: "請輸入您的賬號" }],password: [{ required: true, trigger: "blur", message: "請輸入您的密碼" }],// 不再需要這個驗證// code: [{ required: true, trigger: "change", message: "請輸入驗證碼" }]},loading: false,// 驗證碼開關captchaEnabled: true,redirect: undefined};},watch: {$route: {handler: function(route) {this.redirect = route.query && route.query.redirect;},immediate: true}},created() {//this.getCode();this.getCookie();},methods: {//注釋原先的獲取驗證碼方法/*getCode() {getCodeImg().then(res => {this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;if (this.captchaEnabled) {this.codeUrl = "data:image/gif;base64," + res.img;this.loginForm.uuid = res.uuid;}});},*/getCookie() {const username = Cookies.get("username");const password = Cookies.get("password");const rememberMe = Cookies.get('rememberMe')this.loginForm = {username: username === undefined ? this.loginForm.username : username,password: password === undefined ? this.loginForm.password : decrypt(password),rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)};},hideCaptcha() {this.captchaVisible = falsethis.show = false;},// 獲取圖形驗證碼initCaptcha() {this.$refs.loginForm.validate(valid => {if (valid) {captcha().then(res => {if (res) {this.captcha = res["captcha"];this.loginForm.id = res["id"];this.captchaVisible = truethis.show = true;}})}})},// 登錄方法handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {this.loading = true;if (this.loginForm.rememberMe) {Cookies.set("username", this.loginForm.username, { expires: 30 });Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });} else {Cookies.remove("username");Cookies.remove("password");Cookies.remove('rememberMe');}// 從子組件獲取值this.loginForm.sliderCaptchaTrack = this.$refs.sliderCaptcha.checkParamthis.$store.dispatch("Login", this.loginForm).then(() => {// console.info("this.redirect", this.redirect)this.$router.push({ path: this.redirect || "/" }).catch(()=>{});}).catch(() => {this.loading = false;//調用子組件的刷新圖形驗證碼的方法this.$refs.sliderCaptcha.refreshCaptcha()});}});}}
};
</script><style rel="stylesheet/scss" lang="scss">
<!--新增遮蔽層,其他省略-->
.mask {box-sizing: border-box;position: fixed;top: 0;left: 0;bottom: 0;right: 0;z-index: 1001;background: rgba(0, 0, 0, 0.3);transition: all 0.5s;display: flex;flex-direction: column;justify-content: center;align-items: center;
}
</style>

最后this.$store.dispatch("Login", this.loginForm)調用的Login也需要修改一下,在user.js里面。
在這里插入圖片描述

最終效果
在這里插入圖片描述
點擊【登錄】按鈕
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/39241.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/39241.shtml
英文地址,請注明出處:http://en.pswp.cn/web/39241.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從游戲到營銷:抽卡機小程序的多維度應用探索

在數字化時代&#xff0c;小程序作為一種輕量級、即用即走的應用形態&#xff0c;正逐步滲透到人們生活的方方面面。其中&#xff0c;抽卡機小程序以其獨特的趣味性和互動性&#xff0c;不僅在游戲領域大放異彩&#xff0c;更在營銷領域展現出廣闊的應用前景。本文將從游戲起源…

ELFK簡介

&#x1f468;?&#x1f393;博主簡介 &#x1f3c5;CSDN博客專家 ??&#x1f3c5;云計算領域優質創作者 ??&#x1f3c5;華為云開發者社區專家博主 ??&#x1f3c5;阿里云開發者社區專家博主 &#x1f48a;交流社區&#xff1a;運維交流社區 歡迎大家的加入&#xff01…

vtk跨節點并行渲染

VTK&#xff08;Visualization Toolkit&#xff09;是一個用于科學計算可視化的開源庫。在處理大型數據集時&#xff0c;通常需要進行跨節點&#xff08;分布式處理&#xff09;并行處理以提升性能。VTK支持使用MPI&#xff08;Message Passing Interface&#xff09;庫進行并行…

.net core Redis 使用有序集合實現延遲隊列

Redis 有序集合和集合一樣也是 string 類型元素的集合,且不允許重復的成員。 不同的是每個元素都會關聯一個 double 類型的分數。redis 正是通過分數來為集合中的成員進行從小到大的排序。 有序集合的成員是唯一的,但分數(score)卻可以重復。 集合是通過哈希表實現的&#xf…

Hadoop-11-MapReduce JOIN 操作的Java實現 Driver Mapper Reducer具體實現邏輯 模擬SQL進行聯表操作

章節內容 上一節我們完成了&#xff1a; MapReduce的介紹Hadoop序列化介紹Mapper編寫規范Reducer編寫規范Driver編寫規范WordCount功能開發WordCount本地測試 背景介紹 這里是三臺公網云服務器&#xff0c;每臺 2C4G&#xff0c;搭建一個Hadoop的學習環境&#xff0c;供我學…

文件掃描pdf怎么弄?5個簡易高效的文件掃描方法

在繁忙的工作中&#xff0c;我們常常需要將紙質文件快速轉換為電子文檔&#xff0c;以便于編輯、存儲或分享。 無論是合同、報告還是筆記&#xff0c;將這些紙質文件轉換為Word格式&#xff0c;不僅能提高工作效率&#xff0c;還能確保信息的安全備份。然而&#xff0c;面對市…

前端領域創作者紀念日:回顧與展望

引言 在2048天前&#xff0c;我加入了CSDN。本文將帶您回顧前端技術的發展歷程&#xff0c;探索前端創作者的貢獻&#xff0c;并展望未來的發展方向。 前端技術的發展歷程 前端技術的發展可以追溯到互聯網的早期時代。最初的網頁主要是靜態的HTML文檔&#xff0c;內容簡單&…

57、Flink 的項目配置概述

1&#xff09;概覽 1.開始 要開始使用 Flink 應用程序&#xff0c;請使用以下命令、腳本和模板來創建 Flink 項目。 可以使用如下的 Maven 命令或快速啟動腳本&#xff0c;基于原型創建一個項目。 a&#xff09;Maven 命令 mvn archetype:generate \-Darch…

開源大模型的中流砥柱——LLaMA

元宇宙平臺公司在近年來大力發展人工智能技術,尤其在大規模語言模型(LLM)領域取得了顯著進展。其代表性作品LLaMA(Large Language Model)及其后續版本LLaMA 2和LLaMA 3,成為了業界關注的焦點。 LLaMA模型的發布與許可 LLaMA模型的發布標志著在自然語言處理(NLP)領域的…

使用 Spring Security 配置 HTTPS

引言 為了保護敏感數據免受網絡攻擊&#xff0c;在 Web 應用中使用 HTTPS 是必不可少的。HTTPS 提供了數據傳輸的加密&#xff0c;確保數據在客戶端和服務器之間傳輸時的安全性。Spring Security 提供了簡單的配置方式來實現 HTTPS。本文將詳細介紹如何在 Spring Boot 項目中配…

wordpress建站用付費模板還是免費模板

在WordPress建站時&#xff0c;選擇模板是一個重要的決策。我們可以看到免費和付費模板各有優缺點。 免費模板的主要優點是成本效益。對于預算有限的個人或小企業來說&#xff0c;免費模板是一個理想的選擇&#xff0c;因為它們不需要任何費用。此外&#xff0c;免費模板通常與…

Redis 7.x 系列【16】持久化機制之 AOF

有道無術&#xff0c;術尚可求&#xff0c;有術無道&#xff0c;止于術。 本系列Redis 版本 7.2.5 源碼地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目錄 1. 概述2. 執行原理2.1 Redis 6.x2.1.1 直接寫2.1.2 重寫 2.2 Redis 7.x2.2.1 Redis 6…

Spring Ioc學習

第二章 Spring IOC 章節內容 Spring IOC技術實現Spring IOC設值注入Spring IOC構造注入 章節目標 掌握Spring IOC技術實現掌握Spring IOC設置注入掌握Spring IOC構造注入 第一節 Spring簡介 1. Spring 簡介 Spring 是目前主流的 Java 開發框架&#xff0c;是 Java 世界最…

基于Springboot+Vue+mysql倉庫管理系統倉庫進銷存管理系統

博主介紹&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C編程語言&#xff0c;同時也熟練掌握微信小程序、Php和Android等技術&#xff0c;能夠為大家提供全方位的技術支持和交流。 我有豐富的成品Java、Python、C#畢設項目經驗&#xff0c;能夠為學生提供各類…

Vue 父子頁面使用指南

Vue3父子頁面使用指南 Vue3作為一種現代化的前端框架&#xff0c;提供了強大的組件化功能&#xff0c;使得頁面開發更加模塊化和可維護。本文將深入探討Vue3中父子頁面的使用方法&#xff0c;包括如何傳遞參數、父組件如何調用子組件的方法&#xff0c;以及父子頁面的加載原理…

為什么面向對象的設計方法逐漸減少

在軟件開發領域&#xff0c;面向對象設計&#xff08;Object-Oriented Design, OOD&#xff09;曾經是主導的編程范式。它的主要特征是通過類和對象來組織代碼&#xff0c;并利用繼承、封裝和多態性等特性來實現代碼復用和模塊化。然而&#xff0c;近年來&#xff0c;隨著前端開…

【Python】Python中的數據類型

數據類型 導讀一、數據類型的分類1.1 Number&#xff08;數字&#xff09;1.1.1 靜態數據類型1.1.2 動態數據類型 1.2 String&#xff08;字符串&#xff09;1.3 bool&#xff08;布爾類型&#xff09; 二、數據類型的轉換2.1 隱式類型轉換2.2 顯式類型轉換2.2.1 int(x[,base])…

系統運維面試總結(shell編程)

SYNDDOS攻擊&#xff0c;需要判斷這個訪問是正常訪問還是信包攻擊&#xff0c;當前這個信包發起的訪問數量是多少&#xff0c;例如看到30個信包同時再訪問時設置監控報警。 一般選用/dev/urandom生成&#xff0c;但其生成的隨機數帶有二進制亂碼&#xff0c;所以需要tr命令…

光源基礎知識及選型原則

光的基礎知識 1.光譜(專業理解):光能量在不同頻率上的分布。 2.可見光的波段在380mm—700mm之間。紅光波長最長,為700mm左右,紫光波長最短,在380mm左右。 3.色溫(以白色為界):光源的顏色與黑體在某一溫度下輻射光的顏色相同(或最相近)時,黑體的溫度就稱為該光源…

CASS中按指定距離和方向移動圖形

1、繪制一個圖形 打開軟件&#xff0c;隨意繪制一個矩形&#xff0c;并量取左下角點的坐標值&#xff0c;具體如下&#xff1a; 2、按距離移動原理講解 例1&#xff1a;將圖形沿著y軸負方向移動100米&#xff0c;如何實現&#xff1f; 如上圖所示&#xff0c;測繪中的坐標系…