Spring Boot + Android 实现登录功能
在移动互联网的今天,许多应用需要通过移动端实现与服务器的交互功能,其中登录是最常见且基础的一种功能。通过登录,用户可以获得独特的身份标识,从而访问特定的资源或服务。本篇博客将详细介绍如何使用 Spring Boot 和 Android 实现一个完整的登录功能,从后端 API 的构建到 Android 端的交互,旨在为读者提供一套完整的解决方案。
1. 简单分析
在讨论如何实现登录功能之前,我们需要明确需求。通常情况下,登录功能会包含以下几个需求:
- 用户登录:用户通过输入用户名(或手机号、邮箱)和密码进行登录。
- 身份验证:服务器需要验证用户身份是否合法,是否拥有访问权限。
- Token 授权:为了避免频繁的登录操作,服务器可以返回一个 token,客户端持有该 token 后,能够在一段时间内免除再次登录。
- 安全性:需要防止常见的攻击手段,如密码泄露、暴力破解等。
在本项目中,我们将采用基于 JWT(JSON Web Token) 的方式来实现无状态的登录功能,Spring Boot 作为后端框架,Android 作为前端实现登录页面及 Token 管理。
2. 项目环境配置
2.1 后端:Spring Boot 配置
首先,我们需要在后端使用 Spring Boot 作为服务端框架,选择 Spring Security 进行用户身份验证,并使用 JWT 实现无状态的登录管理。
-
创建 Spring Boot 项目
可以通过 Spring Initializr 快速生成项目骨架,选择如下依赖:- Spring Web
- Spring Security
- Spring Data JPA
- MySQL(或其他数据库)
- JWT(通过 Maven 手动引入依赖)
-
JWT 依赖引入
在pom.xml
文件中添加 JWT 的依赖:<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version> </dependency> <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.2</version> </dependency> <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version> </dependency>
2.2 前端:Android 项目配置
在 Android 中,我们可以使用 Retrofit 作为网络请求库,并通过 SharedPreferences
来存储 token 信息。
-
Retrofit 依赖引入
在 Android 项目的build.gradle
文件中添加 Retrofit 及其相关依赖:implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
-
设计用户登录界面
登录界面是用户进行身份验证的入口,通常包含用户名(或手机号)、密码输入框,以及登录按钮。
3. Spring Boot 后端开发
在这一部分,我们将重点介绍后端的开发,首先从用户模型的设计开始,然后是 Spring Security 的配置,接着是 JWT 的集成与登录 API 的实现。
3.1 用户模型设计
为了保存用户信息,我们首先需要设计一个用户模型。在这里,我们使用 JPA(Java Persistence API)来定义用户实体,并将其持久化到数据库中。
@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;private String password;private String email;// other fields, getters and setters
}
同时,使用 UserRepository
进行数据操作:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {Optional<User> findByUsername(String username);
}
3.2 Spring Security 配置
Spring Security 是 Spring 框架提供的强大的安全管理模块。在这里,我们需要对 Spring Security 进行配置,使其与 JWT 配合使用,来实现无状态的身份验证。
3.2.1 安全配置类
创建一个 SecurityConfig
类,用于配置 Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationFilter jwtAuthenticationFilter;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated().and().addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
这里我们禁用了 CSRF 保护,因为我们将使用 JWT 进行身份验证。我们也配置了 jwtAuthenticationFilter
,它将在每次请求时验证 JWT。
3.3 JWT 的集成
JWT 是一种用于在网络应用之间安全传输信息的紧凑令牌。每个 JWT 都由三部分组成:Header、Payload 和 Signature。下面,我们来实现生成和解析 JWT 的逻辑。
3.3.1 JwtTokenUtil 工具类
创建一个 JwtTokenUtil
工具类,用于生成和验证 JWT。
@Component
public class JwtTokenUtil {private static final String SECRET_KEY = "your_secret_key";public String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();}public String extractUsername(String token) {return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();}public boolean validateToken(String token, UserDetails userDetails) {final String username = extractUsername(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}private boolean isTokenExpired(String token) {final Date expiration = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();return expiration.before(new Date());}
}
3.3.2 JwtAuthenticationFilter
JwtAuthenticationFilter
用于拦截请求并验证 token,确保只有经过身份验证的用户可以访问受保护的资源。
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {final String authorizationHeader = request.getHeader("Authorization");String username = null;String jwt = null;if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {jwt = authorizationHeader.substring(7);username = jwtTokenUtil.extractUsername(jwt);}if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);if (jwtTokenUtil.validateToken(jwt, userDetails)) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}}filterChain.doFilter(request, response);}
}
3.4 登录 API 实现
在服务器端,我们需要提供一个登录的 API,用户通过该 API 发送用户名和密码,服务器验证后生成 JWT 返回给客户端。
@RestController
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Autowiredprivate UserDetailsService userDetailsService;@PostMapping("/login")public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthRequest authRequest) throws Exception {try {authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword()));} catch (BadCredentialsException e) {throw new Exception("Incorrect username or password", e);}final UserDetails userDetails = userDetailsService.loadUserByUsername(authRequest.getUsername());final String jwt = jwtTokenUtil.generateToken(userDetails);return ResponseEntity.ok(new AuthResponse(jwt));}
}
这里,AuthRequest
是用户登录时发送的请求对象,包含用户名和密码。而 AuthResponse
是服务器返回的响应对象,包含生成的 JWT。
4. Android 前端开发
接下来,我们将在 Android 中实现登录页面,并与 Spring Boot 后端进行交互。
4.1 使用 Retrofit 进行网络请求
Retrofit 是 Android 平台上广泛使用的网络请求库。首先,我们定义一个接口用于请求登录 API。
public interface ApiService {@POST("login")Call<AuthResponse> login(@Body AuthRequest authRequest);
}
AuthRequest
类对应后端的登录请求体,AuthResponse
类则用来接收服务器返回的 JWT。
public class AuthRequest {private String username;private String password;// Constructor, getters and setters
}public class AuthResponse {private String jwt;// Constructor, getters and setters
}
4.2 登录页面设计与实现
接下来,我们设计一个简单的登录界面,包括两个 EditText 组件用于输入用户名和密码,外加一个 Button 进行登录操作。
<EditTextandroid:id="@+id/etUsername"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Username" /><EditTextandroid:id="@+id/etPassword"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Password"android:inputType="textPassword" /><Buttonandroid:id="@+id/btnLogin"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Login" />
在 MainActivity.java
中实现登录逻辑:
public class MainActivity extends AppCompatActivity {private EditText etUsername;private EditText etPassword;private Button btnLogin;private ApiService apiService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etUsername = findViewById(R.id.etUsername);etPassword = findViewById(R.id.etPassword);btnLogin = findViewById(R.id.btnLogin);Retrofit retrofit = new Retrofit.Builder().baseUrl("http://your-server-url/").addConverterFactory(GsonConverterFactory.create()).build();apiService = retrofit.create(ApiService.class);btnLogin.setOnClickListener(v -> login());}private void login() {String username = etUsername.getText().toString();String password = etPassword.getText().toString();AuthRequest authRequest = new AuthRequest(username, password);Call<AuthResponse> call = apiService.login(authRequest);call.enqueue(new Callback<AuthResponse>() {@Overridepublic void onResponse(Call<AuthResponse> call, Response<AuthResponse> response) {if (response.isSuccessful()) {String jwt = response.body().getJwt();// Store JWT in SharedPreferencesSharedPreferences preferences = getSharedPreferences("my_prefs", MODE_PRIVATE);preferences.edit().putString("jwt", jwt).apply();// Navigate to another activity} else {// Handle failure}}@Overridepublic void onFailure(Call<AuthResponse> call, Throwable t) {// Handle network failure}});}
}
4.3 Token 的存储和管理
为了在后续的请求中使用 JWT,我们可以将其存储在 Android 的 SharedPreferences
中。这样,用户登录后,应用在关闭再打开时依然可以保持登录状态。
(Call<AuthResponse> call, Response<AuthResponse> response) {if (response.isSuccessful()) {AuthResponse authResponse = response.body();String token = authResponse.getJwt();// Store the token using SharedPreferencesSharedPreferences sharedPreferences = getSharedPreferences("MyApp", MODE_PRIVATE);SharedPreferences.Editor editor = sharedPreferences.edit();editor.putString("JWT_TOKEN", token);editor.apply();Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();// Navigate to another activity after successful loginIntent intent = new Intent(MainActivity.this, DashboardActivity.class);startActivity(intent);finish();} else {Toast.makeText(MainActivity.this, "Login failed", Toast.LENGTH_SHORT).show();}}@Overridepublic void onFailure(Call<AuthResponse> call, Throwable t) {Toast.makeText(MainActivity.this, "Network error", Toast.LENGTH_SHORT).show();}});}
}
在上面的代码中,login()
方法负责发送登录请求并处理服务器的响应。如果登录成功,我们将获取到服务器返回的 JWT 并将其存储在 SharedPreferences
中,以便在后续的请求中使用该 Token 进行身份验证。
4.3 Token 的存储和管理
为了保证用户登录后的身份验证,客户端需要将服务器返回的 JWT 存储起来。SharedPreferences
是 Android 中一种轻量级的数据存储方式,非常适合保存类似于 Token 这样的配置信息。
SharedPreferences sharedPreferences = getSharedPreferences("MyApp", MODE_PRIVATE);
String token = sharedPreferences.getString("JWT_TOKEN", null);
在需要身份验证的请求中,我们可以从 SharedPreferences
中读取保存的 Token,并在请求头中添加该 Token。
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(chain -> {Request originalRequest = chain.request();String token = sharedPreferences.getString("JWT_TOKEN", null);if (token != null) {Request newRequest = originalRequest.newBuilder().header("Authorization", "Bearer " + token).build();return chain.proceed(newRequest);}return chain.proceed(originalRequest);}).build();
通过上述代码,所有发送的请求将携带 JWT,服务端能够通过验证 Token 来判断用户是否具有访问权限。
5. 完整登录流程分析
- 用户在 Android 客户端输入用户名和密码,点击登录按钮。
- 客户端发送 POST 请求到服务器的
/login
接口,请求体中包含用户名和密码。 - 服务器验证用户的身份,如果验证成功,则生成 JWT 并返回给客户端。
- 客户端接收到 JWT 后,将其存储在
SharedPreferences
中。 - 后续请求时,客户端将 JWT 附加在请求头中,服务器根据 JWT 来判断用户是否有权限访问资源。
6. 安全性及优化策略
6.1 HTTPS 加密传输
为了确保数据传输的安全性,建议在实际项目中使用 HTTPS 进行加密传输,避免用户的敏感信息(如密码)被窃取。
6.2 密码加密存储
在服务器端,用户的密码不应该以明文形式存储。通常,我们会使用 BCrypt
等加密算法对用户密码进行加密后再存储到数据库中。
@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}
6.3 Token 的过期管理
JWT 通常会设置一个过期时间,以确保 Token 不会被长期滥用。客户端在检测到 Token 过期时,应提示用户重新登录。
6.4 防止暴力破解
为了防止恶意用户通过暴力破解获取用户密码,建议在登录接口上增加防护机制,如使用验证码,或在多次登录失败后暂时锁定用户账号。
7. 总结
本篇博客介绍了如何使用 Spring Boot 和 Android 实现一个完整的登录功能。从用户模型的设计、Spring Security 的配置、JWT 的集成,到 Android 客户端的登录页面实现、网络请求和 Token 管理,涵盖了从后端到前端的所有关键步骤。登录功能虽然看似简单,但其背后涉及的安全性和可扩展性都是我们需要重点关注的。
相关文章:
Spring Boot + Android 实现登录功能
在移动互联网的今天,许多应用需要通过移动端实现与服务器的交互功能,其中登录是最常见且基础的一种功能。通过登录,用户可以获得独特的身份标识,从而访问特定的资源或服务。本篇博客将详细介绍如何使用 Spring Boot 和 Android 实…...
【通俗理解】边际化技巧在概率论中的应用——从公式到实例
【通俗理解】边际化技巧在概率论中的应用——从公式到实例 关键词提炼 #边际化技巧 #概率论 #联合概率 #条件概率 #积分计算 #概率分布 #贝叶斯推断 第一节:边际化技巧的类比与核心概念【尽可能通俗】 边际化技巧,就像是你在一个复杂的概率迷宫中&am…...
Chen_AdaMV-MoE_Adaptive_Multi-Task_Vision_Mixture-of-Experts 译文
摘要 稀疏激活的专家混合(MoE)正在成为多任务学习(MTL)的一个有前途的范例。 MoE 不是将多个任务的知识压缩到单个模型中,而是分离参数空间,仅利用给定任务类型及其输入的相关模型片段,从而提供…...
多线程下使用数据库 - 20241124
问题 并发性较低,每秒千次但是较高一致性,比如利用数据库中的数据进行判断是否执行某个操作 存在的问题是,如何只锁定判断相关的数据,而不影响数据库操作无关数据。脏读/不可重复读/幻读 解决方案 利用数据InnoDB引擎的LBCC和…...
GMAN解读(论文+代码)
一、注意力机制 注意力机制与传统的卷积神经网络不同的是,前者擅长捕获全局依赖和长程关系,权重会动态调整。而后者对于所有特征都使用同一个卷积核。关于更多注意力机制内容,详见: 注意力机制、自注意力机制、多头注意力机制、通…...
《文件操作》
一 . 文本文件和二进制文件 根据数据的组织形式,数据文件被分为了二进制文件和文本文件 数据在内存中是以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件。 如果要求在外存上以ASCII 码的形式存储,则需要再存…...
【君正T31开发记录】8.了解rtsp协议及设计模式
前边搞定了驱动,先不着急直接上手撸应用层的代码,先了解一下大致要用到的东西。 设计PC端先用vlc rtsp暂时H264编码(vlc好像不支持h265,这个后边我试试)的视频流,先需要支持上rtsp server,了解rtsp协议是必…...
C++菜鸟教程 - 从入门到精通 第三节
上节课的题 上节课的题,大家都做出来了吗? 看一下这道题: 题目描述 N!1*2*...*N; 例5!1*2*3*4*5120. 编程求1!2!3!...N!. 输入 输入一行,只有一个整数n (1<n<10) 输出 输出只有一行(这意味着末尾有一个回车符号),包括1…...
原生JS和CSS,HTML实现开屏弹窗
开屏弹窗常应用于打开游戏,或者打开网站的时候,跳出来在正中间,来显示一些信息,并可以设置今日不再显示 CSS代码如下 <style>#box {width: 100vw;height: 100vh;background-color: rgba(0, 0, 0, 0.2);position: relative…...
微软发布Win11 24H2系统11月可选更新KB5046740!
系统之家11月22日报道,微软针对Win11 24H2系统推出2024年11月最新可选更新补丁KB5046740,更新后系统版本后升至26100.2454,此次更新后修复当应用程序以PDF和XLSX格式导出图表对象时停止响应、无法使用API查找旋转信息等问题。以下小编将给大家…...
【Rabbitmq篇】高级特性----TTL,死信队列,延迟队列
目录 一.TTL 1.设置消息的TTL 2.设置队列的TTL 3.俩者区别 二.死信队列 定义: 消息成为死信的原因: 1.消息被拒绝(basic.reject 或 basic.nack) 2.消息过期(TTL) 3.队列达到最大长度 编辑 …...
【Linux】gcc/g++使用
编译 我们知道,gcc只能编译C,g既能编译C,也能编译C。 由于两者的选项是相同的,这里我们使用gcc来说明。 这就是一个我们在linux中gcc编译一段代码后会自动生成一个a.out为名的可执行文件,然后我们./a.out,…...
IDEA2023 SpringBoot整合MyBatis(三)
一、数据库表 CREATE TABLE students (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT,gender ENUM(Male, Female, Other),email VARCHAR(100) UNIQUE,phone_number VARCHAR(20),address VARCHAR(255),date_of_birth DATE,enrollment_date DATE,cours…...
Java网络编程 - cookiesession
cookie 之前学习了 Okhttp3 库可以调用API、抓取网页、下载文件。但是这些操作都是不要求登录的,如果 API、网页、文件等内容要求登录才能访问,就需要学习新的 cookie 相关的知识。 下面以豆瓣为例,使用 Java 程序读取“我的豆瓣”页面内容…...
100.【C语言】数据结构之二叉树的堆实现(顺序结构) 1
目录 1.顺序结构 2.示意图 编辑 从物理结构还原为逻辑结构的方法 3.父子节点编号的规律 4.顺序存储的前提条件 5.堆的简介 堆的定义 堆的两个重要性质 小根堆和大根堆 6.堆的插入 7.堆的实现及操作堆的函数 堆的结构体定义 堆初始化函数HeapInit 堆插入元素函…...
《Python基础》之循环结构
目录 简介 一、for循环 1、基本语法与作用 2、使用 range() 函数配合 for 循环 3、嵌套的for循环 二、while循环 1、基本语法与作用 2、while 循环嵌套 (1)、while循环与while循环嵌套 (2)、while循环与for循环嵌套 简介 …...
使用JDBC操作数据库
文章目录 使用JDBC操作数据库1. JDBC访问数据库步骤2. Statement与PreparedStatement区别3. JDBC的内容4. JDBC封装4.1 为什么进行JDBC封装4.2 实现JDBC封装4.3 什么是DAO4.4 配置数据库访问参数4.5 配置数据库连接池使用之JNDI的方式 5. 单例模式5.1 懒汉模式5.2 饿汉模式 使用…...
轻松解析 PDF 文档:深入了解 Python 的 pdfplumber 库
轻松解析 PDF 文档:深入了解 Python 的 pdfplumber 库 PDF 是一种常见的文件格式,广泛用于报告、文档、表单等领域。然而,如何高效解析 PDF 内容(尤其是文本和表格),一直是开发者面临的挑战。pdfplumber 是…...
实验五 时域采样与频域采样
时域采样理论的验证 【实例3-1】近似绘制x (n) R4n 在(0,2 π \pi π ) 上的幅频响应曲线( F T [ x ( n ) ] FT[x(n)] FT[x(n)] )。 x [1, 1, 1, 1]; N 64; xk fft(x, N); figure; subplot(2, 1, 1); stem(0:3, x, .); subplot(2, 1, 2); k 0:N-1; plot(2*k/N, abs(x…...
爬虫cookie反爬------加速乐(jsl)
加速乐 反爬虫技术:加速乐采用了包括OB混淆、动态加密算法和多层Cookie获取等高级反爬虫技术,确保整体校验的严密性。关键校验字段位于Cookie中的 __jsl_clearance_s,其验证过程通常涉及三次关键的请求,有效抵御恶意爬虫的侵扰。…...
设计模式——解释器模式
定义: 解释器模式是一种行为设计模式,它给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在这种模式中,通常会将一个复杂的表达式(如数学表达…...
sorted()函数
sorted(iterable, keyNone, reverseFalse)iterable: 需要排序的可迭代对象(如列表、元组、字符串等)。 key: 一个函数,用于从每个元素中提取排序的依据。如果未指定,默认直接比较元素本身。 reverse: 一个布尔值,Tru…...
动静态分析
静态分析 获取哈希值: 查壳: 导出函数: 获取资源信息: 通过发现dos头和pe头,来确定它是个可执行程序。 动态分析...
2024年信号处理与神经网络应用国际学术会议(SPNNA 2024)
重要信息 会议时间:2024年12月13-15日 会议地点:中国武汉 会议官网:www.spnna.org 会议简介 2024年信号处理与神经网络应用国际学术会议(SPNNA 2024)将于2024年12月13日至15日在中国武汉召开。本次会议旨在为全球研…...
winfrom快速自适应
在软件界面设计中,我们通常需要添加各种布局器和规则来实现界面布局,但对于不太熟练的工程师来说,这可能存在一定难度。这里要分享一种自适应布局的方法,它可以根据界面比例自动缩放内容控件,在较短时间内完成软件布局…...
VMware16安装macOS12【详细教程】
因为在应用上线IOS应用商店时,需要用到mac系统进行,于是就在VMware16pro虚拟机进行安装macOS12系统,安装的过程做了一个记录,希望对你有所帮助! 前言 首先需要下载好下面工具: VMware workstation pro 16…...
【设计模式】【创建型模式(Creational Patterns)】之单例模式
单例模式是一种常用的创建型设计模式,其目的是确保一个类只有一个实例,并提供一个全局访问点。 单例模式的原理 单例模式的核心在于控制类的实例化过程,通常通过以下方式实现: 私有化构造函数,防止外部直接实例化。…...
【1.2 Getting Started--->Installation Guide】
NVIDIA TensorRT DOCS 此 NVIDIA TensorRT 10.6.0 安装指南提供安装要求、TensorRT 包中包含的内容列表以及安装 TensorRT 的分步说明。 安装指南 摘要: 本 NVIDIA TensorRT 10.3.0 安装指南提供了安装要求、TensorRT 软件包中包含的内容列表以及安装 TensorRT 的…...
Vue 中 data 属性为函数的深度剖析:原理、区别与实践
在 Vue.js 中,data 属性通常是一个 函数 而不是一个对象,这背后有一系列设计上的原因和原理,尤其是与 Vue 的组件系统、实例化机制、以及响应式数据的管理有关。下面我将详细解答这个问题,并结合实际项目示例和代码分析,进行全面讲解。 1. Vue 中 data 为什么是一个函数而…...
【漏洞复现】H3C 用户自助服务平台 dynamiccontent.properties.xhtml 远程命令执行
免责声明: 本文旨在提供有关特定漏洞的信息,以帮助用户了解潜在风险。发布此信息旨在促进网络安全意识和技术进步,并非出于恶意。读者应理解,利用本文提到的漏洞或进行相关测试可能违反法律或服务协议。未经授权访问系统、网络或应用程序可能导致法律责任或严重后果…...
【技术支持】vscode不使用插件,两种方式重命名html标签对
1. 使用 VS Code 内置功能 VS Code 内置支持 HTML/XML 标签对的重命名功能。步骤如下: 将光标放置在标签名上(如 <div> 或</div>)。按下快捷键 F2(重命名符号)。输入新的标签名,按 Enter&…...
【Seed-Labs 2.0】The Kaminsky Attack Lab
说在前面 本实验属为Seed-Labs 的DNS LAB 中的第二个实验,是第一个实验的延伸,从攻击者和受害者同一个LAN中变成不在同一个LAN中,该系列一共有五个实验: Local DNS Attack LabThe Kaminsky Attack LabDNS Rebinding Attack LabDNS Infrastr…...
node.js中使用express.static()托管静态资源
express.static()定义 express.static(root, [options])是一个中间件函数,负责为Express应用提供静态资源服务。它允许你指定一个或多个目录作为静态资源的根目录,当客户端请求这些资源时,Express会查找并返回对应的文件。 安装express npm i…...
SQL MAX() 函数深入解析
SQL MAX() 函数深入解析 概述 SQL(Structured Query Language)是一种广泛使用的数据库查询语言,它允许用户从数据库中检索、更新和管理数据。在SQL中,MAX() 函数是一个常用的聚合函数,用于从数据集中找出某一列的最大…...
WPF——自定义ToolTip
问题 前一天制作的图标按钮,在测试的过程中发现一个问题:为图标按钮添加的提示如下图所示,它的显示效果非常差,甚至不能看清文本内容,并且其字体与颜色也不是愚所希望的。 产生原因 此是由于tooltip有一个默认的样式…...
linux基本命令(1)
1. 文件和目录操作 ls — 列出目录内容 ls # 显示当前目录的文件和目录 ls -l # 显示详细的文件信息(权限、大小、修改时间等) ls -a # 显示所有文件(包括隐藏文件) ls -lh # 显示详细信息并以易读的方式显示文件大小 cd — 改…...
从0-1逐步搭建一个前端脚手架工具并发布到npm
前言 本文介绍的案例已同步到github,github地址。 vue-cli 和 create-react-app 等 cli 脚手架工具用于快速搭建应用,无需手动配置复杂的构建环境。本文介绍如何使用 rollup 搭建一个脚手架工具。 脚手架工具的工作流程简言为:提供远端仓库…...
开发者视角下的鸿蒙
鸿蒙操作系统(HarmonyOS)是华为公司自主研发的一款面向未来、面向全场景的分布式操作系统。它旨在为用户提供一个无缝的智能生活体验,支持多种终端设备,如智能手机、平板电脑、智能穿戴设备、智能家居等。鸿蒙操作系统的出现&…...
docker基础命令
目录 1、docker拉取镜像 2、查看镜像 3、运行镜像 4、查看容器 5、停止、启动、容器和删除容器 6、进入容器 7、删除镜像 8、保存镜像 9、加载镜像 10、镜像标签 11、制作镜像 12、镜像上传 1、docker拉取镜像 docker pull 用户名/镜像名:tag不加tag(版本号) 即…...
订单日记为“惠采科技”提供全方位的进销存管理支持
感谢温州惠采科技有限责任公司选择使用订单日记! 温州惠采科技有限责任公司,成立于2024年,位于浙江省温州市,是一家以从事销售电气辅材为主的企业。 在业务不断壮大的过程中,想使用一种既能提升运营效率又能节省成本…...
C++共享智能指针
C中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄漏。解决这个问题最有效的方式是使用智能指针。 智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动…...
数学建模学习(138):基于 Python 的 AdaBoost 分类模型
1. AdaBoost算法简介 AdaBoost(Adaptive Boosting)是一种经典的集成学习算法,由Yoav Freund和Robert Schapire提出。它通过迭代训练一系列的弱分类器,并将这些弱分类器组合成一个强分类器。算法的核心思想是:对于被错误分类的样本,在下一轮训练中增加其权重;对于正确分类…...
sqlite-vec一个SQLite3高效向量搜索扩展--JDBC环境使用
最近要用SQLite3,之前放出来了SQLiteUtile工具,方便操作。今天发现AIGC方面,RAG知识库需要使用向量数据库,来存储知识信息。一般呢都是用mysql,但无奈的是mysql就是不让用。突然又发现SQLite3有向量库扩展组件…...
Spark SQL操作
Spark SQL操作 文章目录 Spark SQL操作一、DataFrame的创建与保存1.前提操作2.数据准备3.创建4.保存DataFrame 二、DataFrame的操作1.printSchema2.show3.select4.filter5.groupBy(filed)6.sort(field) 三、临时表操作1.创建临时表2.通过临时表及SQL语句进行查询 四、从RDD转换…...
【大模型】LLaMA: Open and Efficient Foundation Language Models
链接:https://arxiv.org/pdf/2302.13971 论文:LLaMA: Open and Efficient Foundation Language Models Introduction 规模和效果 7B to 65B,LLaMA-13B 超过 GPT-3 (175B)Motivation 如何最好地缩放特定训练计算预算的数据集和模型大小&…...
聚焦AI存储,联想凌拓全力奔赴
【全球存储观察 | 科技热点关注】 每一个时代,都有每一个时代的骄傲。 在信息化时代,NAS文件存储肩负着非结构化数据管理与存储的重任,NetApp以其创新实力,赢得了全球存储市场的极高声誉。 在数智化时代,…...
ansible常用模块
一.ansible常用模块 ansible [主机or组列表] -m 模块 -a "参数"1.shell:类似于在终端上直接输入命令,支持bash特性2.command(默认模块):使用的变量需要事先定义好,不支持bash特性,如管道、重定向3.script: 执行脚本,支持python,shell脚本4.file:用于在被控…...
window11编译pycdc.exe
一、代码库和参考链接 在对python打包的exe文件进行反编译时,会使用到uncompyle6工具,但是这个工具只支持python3.8及以下,针对更高的版本的python则不能反编译。 关于反编译参考几个文章: Python3.9及以上Pyinstaller 反编译教…...
C语言——break、continue、goto
目录 一、break 二、continue 1、在while循环中 2、在for循环中 三、go to 一、break 作用是终止循环,在循环内遇到break直接就跳出循环。 注: 一个break语句只能跳出一层循环。 代码演示: #include<stdio.h>void test01() {for (…...
实战OpenCV之人脸识别
基础入门 随着计算机视觉技术和深度学习的发展,人脸识别已经成为一项广泛应用的技术,涵盖了从安全监控、身份验证、智能家居到大型公共安全项目等多个领域。 人脸识别技术通常包括以下几个主要步骤。 图像采集:通过摄像头或其他图像采集设备,捕获包含人脸的图像或视频帧。 …...