目录

1.制作验证码——java SPI机制

1.1 类所属包情况

1.2 具体实现

1.2.1 核心接口:ICode 

1.2.2 接口实现类:验证码的具体生成逻辑

1.2.3 服务工厂类:CodeServiceFactory(核心:SPI 服务发现)

1.2.4 SPI 配置文件

1.2.5 主程序:App(运行入口)

1.2.6 注释掉不同的配置

2.Java RMI (远程方法调用)

2.1 定义

2.2 实现分布式登录验证系统

2.2.1 数据库准备

2.2.2 在idea中启动Java的RMI服务

2.2.3 在eclipse实现登录


1.制作验证码——java SPI机制

1.1 类所属包情况

1.2 具体实现

1.2.1 核心接口:ICode 

定义验证码生成的标准接口,所有验证码生成实现类都需要实现该接口

package com.hy.interfaces;public interface ICode {public String makeCode();
}

1.2.2 接口实现类:验证码的具体生成逻辑

① 数字验证码实现:NumberCodeImpl

package com.hy.interfaces.impl;import java.util.Random;
import com.hy.interfaces.ICode;public class NumberCodeImpl implements ICode {// 数字字符源(0-9)private String[] nums = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };@Overridepublic String makeCode() {String code = "";for (int i = 0; i < 4; i++) { // 生成4位验证码// 随机获取字符源中的一个元素String s = String.valueOf(new Random().nextInt(nums.length));// 确保字符不重复:如果已包含则重新生成(i--回退循环)if (!code.contains(s)) {code += s;} else {i--;}}return code;}
}

② 中文验证码实现:ChineseCodeImpl

package com.hy.interfaces.impl;import java.util.Random;
import com.hy.interfaces.ICode;public class ChineseCodeImpl implements ICode {// 中文字符源(自定义汉字)private String[] nums = { "赵", "钱", "孙", "李", "王", "五", "马", "六", "天", "地" };@Overridepublic String makeCode() {String code = "";for (int i = 0; i < 4; i++) { // 生成4位验证码// 随机获取字符源中的一个元素String s = nums[new Random().nextInt(nums.length)];// 确保字符不重复:如果已包含则重新生成(i--回退循环)if (!code.contains(s)) {code += s;} else {i--;}}return code;}
}

1.2.3 服务工厂类:CodeServiceFactory(核心:SPI 服务发现)

利用 Java 的 ServiceLoader 类实现 SPI 机制的服务发现:通过接口(ICode.class)动态加载其所有实现类

package com.hy.service;import java.util.Iterator;
import java.util.ServiceLoader;
import com.hy.interfaces.ICode;public class CodeServiceFactory {public static String createCode(Class targetClass) {// 1. 通过ServiceLoader动态加载实现了targetClass(此处为ICode)的服务实现类ServiceLoader s = ServiceLoader.load(targetClass);// 2. 获取实现类的迭代器Iterator its = s.iterator();ICode code = null;// 3. 迭代获取最后一个实现类(若有多个实现,取最后一个)while (its.hasNext()) {code = (ICode) its.next();}// 4. 调用实现类的makeCode()生成验证码String checkCode = code.makeCode();return checkCode;}
}

1.2.4 SPI 配置文件

# 开头的行是注释,不会被加载,需要实现哪个,就把其余注释掉

com.hy.interfaces.impl.NumberCodeImpl
#com.hy.interfaces.impl.ChineseCodeImpl

1.2.5 主程序:App(运行入口)

主方法通过无限循环,每 6 秒调用一次工厂类的createCode方法,生成验证码

package com.hy.javaspi;import com.hy.interfaces.ICode;
import com.hy.service.CodeServiceFactory;public class App {public static void main(String[] args) {while (true) { // 无限循环// 调用工厂类生成验证码(基于ICode接口的实现类)String checkCode = CodeServiceFactory.createCode(ICode.class);System.out.println("获取的验证码为:" + checkCode);try {Thread.sleep(6000); // 每6秒生成一次} catch (InterruptedException e) {e.printStackTrace();}}}
}

1.2.6 注释掉不同的配置

① 使用数字验证码

com.hy.interfaces.impl.NumberCodeImpl
#com.hy.interfaces.impl.ChineseCodeImpl

输出结果:

获取的验证码为:2834
获取的验证码为:9651
获取的验证码为:0753
获取的验证码为:4702

...

② 使用中文验证码

#com.hy.interfaces.impl.NumberCodeImpl
com.hy.interfaces.impl.ChineseCodeImpl

输出结果:

获取的验证码为:五李孙地
获取的验证码为:钱孙六李
获取的验证码为:赵马地王
获取的验证码为:马五李地

...

2.Java RMI (远程方法调用)

2.1 定义

Java RMI(Remote Method Invocation,远程方法调用)是 Java 原生的分布式通信机制,允许一个 JVM 中的对象(客户端调用另一个 JVM 中的对象(服务端)的方法,就像调用本地方法一样,无需显式处理网络通信细节。

2.2 实现分布式登录验证系统

2.2.1 数据库准备

-- 创建t_emps表 --
CREATE TABLE t_emps(eid INT PRIMARY KEY auto_increment, -- 员工的编号ename VARCHAR(20) NOT NULL, -- 员工的姓名epwd CHAR(8) NOT NULL, -- 员工的密码ebirthday datetime, -- 员工的出生年月,不设计年龄字段,会造成字段冗余esalary DOUBLE NOT NULL, -- 员工的工资eaddress VARCHAR(100), -- 员工的地址estate INT NOT NULL -- 员工的状态
)-- 删除t_emps表 --
DROP TABLE t_emps-- 插入数据 --
INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('张三','11111','2000-05-28',90000.56,'南京',1);INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('李四','22222','2004-06-15',88000.69,'盐城',1);INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('李老八','22222','1996-12-30',5600,'无锡',1);INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('赵二','22222','1996-12-30',5800,'无锡',0);-- 查询表 --
SELECT * FROM t_emps

实现效果:

2.2.2 在idea中启动Java的RMI服务

步骤一:在idea中新建Maven项目,并在pom.xml文件中添加依赖

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.24</version>
</dependency>

步骤二:具体实现

① 类所属包情况

② 数据访问层:Dao类(数据库交互)

通过 JDBC 连接 MySQL 数据库,实现 “登录验证” 的数据库交互逻辑

package com.hy.dao;import java.sql.*;public class Dao {Connection conn; // 数据库连接对象// 构造方法:初始化数据库连接public Dao() {try {// 1. 加载MySQL JDBC驱动(MySQL 8.0+使用com.mysql.cj.jdbc.Driver)Class.forName("com.mysql.cj.jdbc.Driver");// 2. 建立数据库连接// 连接URL:jdbc:mysql://主机:端口/数据库名// 用户名:root,密码:修改为自己的密码conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025", "root", "yourpassword");} catch (ClassNotFoundException e) {e.printStackTrace(); // 驱动类未找到异常} catch (SQLException e) {e.printStackTrace(); // 数据库连接异常}}// 登录验证方法:检查用户名和密码是否匹配public int checkLogin(String username, String userpwd) {// SQL查询:统计符合条件的用户数量(ename=用户名且epwd=密码)String sql = "select count(ename) from t_emps where ename = ? and epwd =?";int count = 0; // 匹配的用户数量(0或1)try {// 使用PreparedStatement预编译SQL,防止SQL注入PreparedStatement pstmt = this.conn.prepareStatement(sql);pstmt.setString(1, username); // 填充第一个参数(用户名)pstmt.setString(2, userpwd);  // 填充第二个参数(密码)// 执行查询,获取结果集ResultSet rs = pstmt.executeQuery();// 读取结果集中的计数(count(ename))while (rs.next()) {count = rs.getInt(1); // 第一列的结果(0或1)}} catch (SQLException e) {e.printStackTrace(); // SQL执行异常} finally {// 关闭数据库连接(避免资源泄露)if (null != conn) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}return count; // 返回匹配数量(1表示登录成功,0表示失败)}
}

③ 远程接口:IData(定义 RMI 通信标准)

定义客户端与服务端的 “通信协议”,明确可远程调用的方法,是 RMI 通信的基础(客户端与服务端必须完全一致)。

package com.hy.data.interfaces;import java.rmi.Remote;
import java.rmi.RemoteException;// 客户端与服务端的远程通信接口(必须继承Remote)
public interface IData extends Remote {// 远程方法:查询消息(必须声明抛出RemoteException)public String queryMessage() throws RemoteException;// 远程方法:登录验证(必须声明抛出RemoteException)public String checkLogin(String username, String userpwd) throws RemoteException;
}

④ 远程接口实现:UserDataImpl(服务端业务逻辑)

实现IData远程接口,封装服务端业务逻辑(调用 Dao 层操作数据库),并通过 RMI 框架导出为 “可远程访问的对象”。

package com.hy.impl;import com.hy.dao.Dao;
import com.hy.data.interfaces.IData;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;// 远程接口的实现类(必须继承UnicastRemoteObject或手动实现序列化)
public class UserDataImpl extends UnicastRemoteObject implements IData {// 构造方法:必须抛出RemoteException(因为父类UnicastRemoteObject的构造方法抛出该异常)public UserDataImpl() throws RemoteException {super(); // 调用父类构造方法,自动处理对象的网络传输(序列化/反序列化)}// 实现远程方法:返回固定消息@Overridepublic String queryMessage() throws RemoteException {return "RMI分布式从远程传过来的数据为:RMI、webservice、hessian、thrift、googleRPC、Dubbo";}// 实现远程方法:调用Dao进行登录验证@Overridepublic String checkLogin(String username, String userpwd) throws RemoteException {Dao dao = new Dao(); // 创建数据访问对象// 调用Dao的checkLogin方法,若返回值>0(即存在匹配用户),返回"登录成功",否则返回"登录失败"if (dao.checkLogin(username, userpwd) > 0) {return "登录成功";}return "登录失败";}
}

⑤ RMI 服务端:ServerRMI(启动并发布服务)

启动 RMI 注册表(服务注册中心)、创建远程对象实例、将远程对象绑定到指定 URL,供客户端查找和调用。

package com.hy.serverrmi;import com.hy.data.interfaces.IData;
import com.hy.impl.UserDataImpl;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;public class ServerRMI {public static void main(String[] args) {try {// 1. 创建远程对象实例(UserDataImpl实现了IData接口)IData datas = new UserDataImpl();// 2. 在本地9200端口注册RMI注册表(类似“服务注册中心”)LocateRegistry.createRegistry(9200);// 3. 将远程对象绑定到RMI URL(客户端通过该URL查找服务)// 格式:rmi://主机:端口/服务名称Naming.bind("rmi://127.0.0.1:9200/userdatas", datas);System.out.println("Java的RMI服务已经启动成功");} catch (RemoteException e) {e.printStackTrace(); // 远程对象创建或注册表启动异常} catch (MalformedURLException e) {e.printStackTrace(); // RMI URL格式错误} catch (AlreadyBoundException e) {e.printStackTrace(); // 服务名称已被绑定(重复发布)}}
}

输出结果:

Java的RMI服务已经启动成功

2.2.3 在eclipse实现登录

① 类所属包情况

② 远程接口:IData(客户端与服务端的通信契约)

客户端与服务端的 “通信协议”,定义客户端可以远程调用的方法。

package com.hy.data.interfaces;import java.rmi.Remote;
import java.rmi.RemoteException;// 远程接口:客户端和服务端必须共享此接口(包路径、方法定义完全一致)
public interface IData extends Remote {// 远程方法1:查询消息(服务端返回预设字符串)public String queryMessage() throws RemoteException;// 远程方法2:登录验证(接收用户名和密码,返回登录结果)public String checkLogin(String username, String userpwd) throws RemoteException;
}

③ 客户端实现类:App(发起远程调用的核心逻辑)

接收用户输入(账号密码),通过 RMI 框架查找服务端远程对象,发起远程调用,最后展示调用结果。

package com.hy.javamiclinet;import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Scanner;
import com.hy.data.interfaces.IData;public class App {// 远程对象引用:客户端通过该引用调用服务端方法static IData data = null;// 静态代码块:初始化远程对象引用(程序启动时执行)static {try {// 关键:通过RMI URL查找服务端绑定的远程对象// URL格式:rmi://服务端IP:端口/服务名称(需与服务端绑定的URL完全一致)data = (IData) Naming.lookup("rmi://127.0.0.1:9200/userdatas");} catch (MalformedURLException e) {e.printStackTrace(); // URL格式错误(如端口无效、协议错误)} catch (RemoteException e) {e.printStackTrace(); // 远程通信异常(如服务端未启动、网络不通)} catch (NotBoundException e) {e.printStackTrace(); // 服务名称未绑定(服务端未发布该服务)}}// 调用远程方法:queryMessage(查询消息)public void queryMsg() {try {// 看似调用本地对象方法,实际通过网络调用服务端的实现String message = data.queryMessage();System.out.println("客户端远程调用服务端的结果为:" + message);} catch (RemoteException e) {e.printStackTrace(); // 远程调用过程中发生异常}}// 调用远程方法:checkLogin(登录验证)public void checkLogin(String username, String userpwd) {try {// 传递参数(用户名和密码)到服务端,调用远程验证方法String result = data.checkLogin(username, userpwd);System.out.println("客户端远程调用服务端登录的结果为:" + result);} catch (RemoteException e) {e.printStackTrace(); // 远程调用异常(如参数传输失败、服务端处理出错)}}// 主方法:程序入口,接收用户输入并发起登录验证public static void main(String[] args) {App app = new App(); // 创建客户端实例// 接收用户输入(用户名和密码)System.out.println("请输入用户姓名:");Scanner s1 = new Scanner(System.in);String username = s1.next(); // 读取用户名System.out.println("请输入用户密码:");Scanner s2 = new Scanner(System.in);String userpwd = s2.next(); // 读取密码// 调用登录验证方法(远程调用)app.checkLogin(username, userpwd);// 可选:调用查询消息方法(注释掉了,取消注释可执行)// app.queryMsg();}
}

输出结果:

请输入用户姓名:
张三
请输入用户密码:
11111
客户端远程调用服务端登录的结果为:登录成功

请输入用户姓名:
张三
请输入用户密码:
22222
客户端远程调用服务端登录的结果为:登录失败

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96202.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96202.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96202.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6笔记5

1. Promise相当于一个容器&#xff0c;保存着未来才要结束的事件&#xff08;异步操作&#xff09;的一个结果&#xff0c;各种异步操作都可以用同样方法处理 axios特点&#xff1a;对象的状态不受外界影响&#xff0c;处理异步操作&#xff0c;3个状态&#xff0c;Pending&…

解决idea2021maven依赖导入后还是找不到包,爆红无法导入

1.依赖导入后pom.xml文件以及Maven,此两处代码还是爆红 2.解决方法 由技术大佬同事几分钟解决,他记忆深刻之前搞过很久,一看就知道哪里出问题了 我之前是配过Maven的本地仓库的但是没有用,这次出问题之后长教训了,技术大佬说尽量用自己的本地仓库,不要用idea的Maven仓库,容易…

【硬件-笔试面试题-81】硬件/电子工程师,笔试面试题(知识点:详细讲讲同步时钟与异步时钟通信)

题目汇总版--链接&#xff1a; 【硬件-笔试面试题】硬件/电子工程师&#xff0c;笔试面试题汇总版&#xff0c;持续更新学习&#xff0c;加油&#xff01;&#xff01;&#xff01;-CSDN博客 【硬件-笔试面试题-81】硬件/电子工程师&#xff0c;笔试面试题&#xff08;知识点…

php计算一个模拟增长过程函数

private function calculateGrowth($progress) {// 使用多个增长阶段模拟不均匀性if ($progress < 0.3) {// 前30%时间&#xff1a;缓慢增长 30 %return pow($progress / 0.3, 0.7) * 0.3;} elseif ($progress < 0.7) {// 中间40%时间&#xff1a;快速增长 50%return 0.3…

华为USG6000v2 NAT模式下IPSEC IKE V1 实验

USG6000v2 NAT模式下IPSEC 实验 拓扑图公网配置OSPF路由协议&#xff08;网络要求能通就行&#xff09; 一、 总部配置 &#xff08;一&#xff09;交换机配置 1、 总部交换机到防火墙网段 192.168.10.0/24 2、 交换机G0/0设置成access端口划分vlan 10&#xff0c;网关 192.168…

android 里设计context的作用

Android中的Context是一个核心设计机制&#xff0c;其作用主要体现在以下几个方面&#xff1a; 1. 提供应用程序环境信息 Context作为抽象类&#xff0c;封装了应用与系统交互所需的全局环境信息&#xff0c;包括资源访问、组件启动、系统服务调用等基础能力。它本质上是应用…

能发弹幕的简单视频网站

界面参考了Youtube&#xff0c;后端使用Spring Boot&#xff0c;前端Vue&#xff0c;vuetifyjs。支持自动生成封面图&#xff0c;发送弹幕、AI内容审核等功能。 一个简单的视频网站 网站名称是 TikTok 与 YouTube 的缝合&#xff0c;Logo 为豆包 AI 生成 主要界面参考了 Yout…

了解网站安全监测系统的重要性

在当今数字化时代&#xff0c;网站已经成为企业发展和品牌推广的关键渠道之一。然而&#xff0c;随之而来的是网络安全威胁的增加&#xff0c;包括数据泄露、恶意攻击和病毒感染等问题。为了保护网站和用户信息的安全&#xff0c;网站安全监测系统变得至关重要。1. 网站安全监测…

fastadmin安装后后台提示putenv()报错,不显示验证码

1.安装fastadmin后&#xff0c;访问项目后台&#xff0c;提示报错&#xff1a;Warning: putenv() has been disabled for security reasons in /www/wwwroot/app.aaa.cn/thinkphp/base.php on line 50 这时候验证码还不显示&#xff0c;怎么解决呢&#xff1f;2.打开php.ini文件…

C语言深度入门系列:第二篇 - 变量与数据类型:程序世界的基本粒子与容器

C语言深度入门系列&#xff1a;第二篇 - 变量与数据类型&#xff1a;程序世界的基本粒子与容器 本章目标 本章将深入探讨程序如何“记住”信息。你将彻底理解变量的本质是内存中的一块空间&#xff0c;数据类型是解释这块内存中0和1的规则。我们将超越简单的int, float用法&…

十一旅游中国气象攻略:如何评估降雨、大风与紫外线

一、十一期间的中国气候态要点(10 月上旬) 冷空气南下增多:华北—东北易大风降温;长江以南易出现冷暖空气交汇降雨。 台风未完全退场:华南沿海与海南、华东沿海仍可能受外围环流与风雨影响。 昼夜温差扩大:西北、华北、内陆盆地早晚凉,白天热,雾/霜风险抬头。 高原与…

鸿蒙项目篇-21-创建项目、修改软件文字/图标

目录 【预览】修改配置文件 module.json5 创建项目 初次-运行预览 拷贝图片 用于替换 【实操】修改配置文件 module.json5 点击,显示引用 ctrl + 点击,引用追踪 置顶模拟器 最终代码 总结 先规划再行动【高效】以终为始【不偏离方向/目标】 【预览】修改配置文件 m…

Linux服务器的系统安全强化超详细教程

Linux服务器几乎承担着最重要的计算和存储角色&#xff0c;它是企业网站、数据库、应用中间件、开发环境乃至云原生容器平台的核心。正因为Linux服务器的广泛应用&#xff0c;它也成为攻击者频繁锁定的目标。系统一旦被攻破&#xff0c;不仅业务会面临中断&#xff0c;更严重的…

计算机毕设 java 高校会议室预约管理系统 基于 SSM 框架的高校会议室管理平台 Java+MySQL 的预约全流程管控系统

计算机毕设java高校会议室预约管理系统z14559 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09;本套源码可以先看具体功能演示视频领取&#xff0c;文末有联xi 可分享在高校会议室资源紧张的背景下&#xff0c;传统预约依赖人工登记、信息传递滞后&#xff0c;存在预…

Redis的持久化机制RDB和AOF详解

本文为您介绍redis的持久化机制以及持久化的选型。 目录 持久化策略 RDB(RedisDatabase)快照 AOF(Append Only File) 混合持久化策略 RDB与AOF对比 持久化策略使用建议 Redis数据备份策略建议 补充知识 save与bgsave对比 bgsave的写时复制(COW)机制 持久化策略 Red…

Vue 3 实战:从零到一用 vue-pdf-embed 打造功能齐全的 PDF 查看器

你好&#xff0c;Vue 开发者们&#xff01; 在 Web 开发中&#xff0c;我们经常会遇到需要在页面中直接展示 PDF 文件的需求&#xff0c;例如预览合同、显示报告或在线阅读文档。你可能会想到用 <iframe> 或者一些重量级的库&#xff0c;但它们往往不够灵活或过于臃肿。…

adb的常用命令

adb devices 用USB数据线连接电脑&#xff0c;查看连接上的设备 adb tcpip 5555 切换计算机的adb为wifi连接模式 adb connect 192.168.2.250:5555 连接手机的ip地址&#xff0c;如果连接成功&#xff0c;则可拔掉数据线 adb 查看adb的相关信息&#xff0c;包括版本号&#xff0…

稳态太阳光模拟器 | 多源分布式设计的要点有哪些?

稳态太阳模拟器的多源分布式设计&#xff0c;是一种通过多组独立光源单元分布式排布、结合稳态光学调控技术&#xff0c;实现对太阳光谱、辐照强度及辐照均匀性精准复现的高端光模拟技术。其核心优势在于突破传统模拟光源在长期工作稳定性、大面积辐照均匀性及能量传递效率上的…

代码随想录 day 35 动态规划

第九章 动态规划part03 正式开始背包问题&#xff0c;背包问题还是挺难的&#xff0c;虽然大家可能看了很多背包问题模板代码&#xff0c;感觉挺简单&#xff0c;但基本理解的都不够深入。 如果是直接从来没听过背包问题&#xff0c;可以先看文字讲解慢慢了解 这是干什么的。 …

大数据探索性分析——抽样技术应用

2.3 概率抽样 一、简单随机抽样 # 数据预处理 LoanStats3c read.csv("D:/OneDrive - stu.fynu.edu.cn/大四上学期/ysq-大数据探索性分析/data/2数据集二&#xff1a;Loan Data--Lending Club/LoanStats3c/LoanStats3c.csv", header TRUE, fill TRUE, comment.char…