Java多线程+网络编程登录管理实例
用户包含管理员和普通用户两个角色进行测试。
假定:管理员用户名:admin,密码:abc 普通用户名:user 密码:123
- 用户从客户端发起登录请求,客户端将数据传递到服务器端,由服务器做验证。服务器端保存用户数据。用户登录成功提示登录成功,并显示功能模块,登录失败提示:用户名或密码不正确。
- 在服务器端启用多线程模式,要求:每一个用户发送登录请求到服务器后,服务器端就分配一个线程去处理这个请求。以实现服务器端多线程模式下的用户登录。
代码实现:
Bean层
1、RequestBody
类请求体继承Serializable:
/**
* 请求体
*/
public class RequestBody implements Serializable {
public static final String LOGIN = "login";//登陆的功能模块
private static final long serialVersionUID = -1593966669454243804L;
private String cmd;//需要操作的功能
private User user;//操作的对象
public String getCmd() {
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
ResponseBody
类响应体继承Serializable
/**
* 响应体
*/
public class ResponseBody implements Serializable {
private static final long serialVersionUID = -6315166158520343036L;
private int result;//响应的结果
private String status;//响应的状态
private boolean ok;//是否登陆成功的状态
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
}
User
登录者类
public class User implements Serializable {
private static final long serialVersionUID = 3646073779387514873L;
private String username,password;//登陆的用户的用户名和密码
public User(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//两个对象是否重复
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(username, user.username) &&
Objects.equals(password, user.password);
}
@Override
public int hashCode() {
return Objects.hash(username, password);
}
}
Dao层
UserDao
类数据层
public class UserDao {
public static final int ADMIN_SUCCESS = 1;//管理员
public static final int USER_SUCCESS = 2;//普通用户
public static final int LOGIN_FAIL = 3;//退出
private HashMap<User, Integer> map = new HashMap<>();//存放是管理员还是用户的
//初始化集合中的信息
{
map.put(new User("admin", "abc"), ADMIN_SUCCESS);
map.put(new User("user", "123"), USER_SUCCESS);
}
//登陆的方法
public int login(User user) {
System.out.println(user);
Integer loginResult = map.get(user);//通过键获取对应的值
System.out.println(loginResult);//输出键对应的值
return loginResult == null ? LOGIN_FAIL : loginResult;//输出对应的管理员和用户的选择的编号
}
}
View层
Views
类视图层,展示菜单以及键值输入等提示信息
public class Views {
//输入的变量的对象
private Scanner sc = new Scanner(System.in);
//简单的提示信息
public void welcome() {
System.out.println("欢迎使用网络版-快递e栈");
}
//选择的变量
public void showMainMenu() {
System.out.println("请选择:1.登录,2.离开");
}
//选择对应的编号
public int inputKey(int max) {
int num = 1;
System.out.println("请输入1~" + max + "的数字:");
String str = sc.nextLine();
try {
num = Integer.parseInt(str);
} catch (NumberFormatException e) {
}
//输入的数字是否是1到max之间的
if (num < 1 || num > max) {
num = inputKey(max);//如果不是的话,重新调用方法,在重新输入一次
}
return num;//在1到max之间的,就直接返回对应的数字
}
//简单的提示信息
public void bye() {
System.out.println("谢谢使用,再见!");
}
//输入的对应的用户名和密码
public User inputUser() {
String username = inputStr("请输入用户名:");
String password = inputStr("请输入密码:");
return new User(username, password);//返回user对象
}
//输入的字符串的信息
private String inputStr(String cmd) {
System.out.println(cmd);
return sc.nextLine();
}
//提示登陆失败的信息
public void loginFail() {
System.out.println("登录失败!");
}
}
Controller层
Client
类客户端
public class Client {
public int login(User user) throws IOException, ClassNotFoundException {
//创建客户端端,一个是连接的ip地址,一个是端口号
Socket socket=new Socket("127.0.0.1",12345);
//创建请求的对象
RequestBody body=new RequestBody();
//设置请求的功能模块
body.setCmd(RequestBody.LOGIN);
body.setUser(user);//设置输入的信息
//写入请求的对象,和请求的内容
writeRequest(socket, body);
//设置响应的对象
ResponseBody responseBody = getResponseBody(socket);
socket.close();//释放客户端资源
return responseBody.getResult();//获取响应的内容
}
//获取响应体
private ResponseBody getResponseBody(Socket socket) throws IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
return (ResponseBody) ois.readObject();
}
private void writeRequest(Socket socket, RequestBody body) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(body);
}
}
Server
服务器端
public class Server {
//数据的操作
private static UserDao userDao=new UserDao();
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建服务器对象。端口号一定要和客户端的端口号一致
ServerSocket ss=new ServerSocket(12345);
while (true) {
//获取客户端连接对象
Socket socket = ss.accept();
//创建一个多线程
new Thread(() -> {
try {
//执行响应的登陆的模块
handleSocket(socket);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}).start();//开启线程
}
}
private static void handleSocket(Socket socket) throws IOException, ClassNotFoundException {
//获取一下请求的内容
RequestBody requestBody = getRequestBody(socket);
// 判断请求的内容是不是对应的模块
switch (requestBody.getCmd()){
case RequestBody.LOGIN:
loginUser(socket,requestBody);
// case ....
break;
}
}
//登陆方法
private static void loginUser(Socket socket,RequestBody requestBody) throws IOException {
//获取请求的user对象
User user = requestBody.getUser();
//管理员还是用户
int result=userDao.login(user);
//创建响应的内容对象
ResponseBody body=new ResponseBody();
//设置响应的结果 管理员还是客户端
body.setResult(result);
//写入对象
writeResponse(socket, body);
}
//写响应的内
private static void writeResponse(Socket socket, ResponseBody body) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(body);
}
private static RequestBody getRequestBody(Socket socket) throws IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
return (RequestBody) ois.readObject();
}
}
Main
public class Main {
//整个程序的流程控制
static Views v = new Views();
static Client c = new Client();
public static void main(String[] args) throws IOException, ClassNotFoundException {
v.welcome();
//1.登录2.离开
boolean flag = true;
while (flag) {
v.showMainMenu();
int key = v.inputKey(2);
switch (key) {
case 1:
loginUser();
break;
case 2:
v.bye();
flag = false;
break;
}
}
}
private static void loginUser() throws IOException, ClassNotFoundException {
User user = v.inputUser();//获取输入的用户对象
int login = c.login(user);//通过对象判断管理员还是用户
switch (login) {
case UserDao
.ADMIN_SUCCESS:
adminLoop();
break;
case UserDao.USER_SUCCESS:
userLoop();
break;
case UserDao.LOGIN_FAIL:
v.loginFail();
break;
}
}
private static void userLoop() {
System.out.println("用户的操作");
}
private static void adminLoop() {
System.out.println("管理员操作");
}
}
测试结果:
Main
客户端:
欢迎使用网络版-快递e栈
请选择:1.登录,2.离开
请输入1~2的数字:
1
请输入用户名:
admin
请输入密码:
abc
管理员操作
请选择:1.登录,2.离开
请输入1~2的数字:
1
请输入用户名:
user
请输入密码:
123
用户的操作
Server
服务器端
User{username='admin', password='abc'}
1
User{username='user', password='123'}
2