实验目标:
1、Java实现一个基于TCP/UDP的网络聊天系统-添加UI和使用持久化技术
2、本系统的持久化技术是使用文件存储,存放到一个excel表格中
3、本系统实现了一个服务器端-多线程监听;客户端可与服务器端实现通信--通信图如下图。
4、其中:本系统实现了局域网通信,如果需要使用本系统,请到通信配置处修改通信IP
项目已开源:
????????gitee: https://gitee.com/TangGarlic/socket-chat-system.git
? ? ? ? github:?https://github.com/TonyTang-dev/javaSocketChatSystem.git
如有改进需求和改进想法,可与作者联系。
实现效果:
1、socket:socket叫套接字,由IP地址和端口号共同组成。每一条TCP 连接唯一地被通信两端的两个端点即两个套接字所确定,形如:
2、端口号:即协议端口号,通常简称为端口(port),通信的终点是应用 进程,可以通过把端口想象成为通信的终点,因为只需要把传送的报文交到目的主机的某一个合适的目的端口,剩下的工作即最后交付目的进程就由TCP完成。在协议栈层间的抽象的协议端口是软件端口,而硬件端口是不同硬件设备进行交互的端口,而软件端口是应用层的各种协议进程与传输实体进行层间交互的一种地址。端口用一个16位端口号进行标志,只具有本地意义,即端口号只是为了标志本计算机应用层中的各进程;在互联网中,不同计算机的相同端口号没有联系。因此两台计算机中的进程要相互通信,不仅需要知道对方的IP地址以找到对方计算机,而且还要知道对方的端口号以找到对方计算机中的应用进程。 3、TCP:即传输控制协议,传送的数据单位协议是TCP报文段,是一 种面向连接的协议,提供面向连接的服务,传送的数据单位协议是TCP报文段,不提供广播或多播服务;由于TCP要提供可靠的、面向连接的传输服务,因此不可避免地增加了许多的开销,这不仅使协议数据单元的首部增大很多,还要占用许多的处理及资源。TCP报文段是在传输层抽象的端到端逻辑信道中传送,是可靠的全双工信道。但这样的信道却不知道究竟经过了那些路由器,而这些路由器也根本不知道上面的传输层是否建立了TCP连接。
4、UDP:即用户数据报协议,传输的数据单位协议是用户数据报,是 一种无连接协议,在传输数据之前不需要先建立连接,传送的数据单位协议是UDP报文或用户数据报;对方的传输层在收到UDP报文后不需要给出任何确认,虽然UDP不提供可靠交付,但在某些情况下UDP是一种最有效的工作方式。UDP用户数据包与网络层的IP数据报有很大差别主要是IP数据报要经过互联网中许多路由器的存储转发,UDP用户数据包是在传输层的端到端抽象的逻辑信道中传送的。 5、注意:UDP传输是基于报文的,而TCP传输是面向字节流的,其中 TCP的字节流中的“流”是指流入或流出进程的字节序列,面向字节流的含义是虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序交下来的数据看成仅仅是一连串无结构的字节流。
实现: 1、因为目前还没有直接连接公网IP的功能,我们采用的是基于局域 网的聊天系统。其中通过连接同一个路由器(本次使用一个手机移动热点作为无线路由器),客户端和服务端都连接至此局域网以实现物理组网。 2、我们对系统的设计为:客户端各个端既是服务器又是客户机,即 客户端之间可以直接收发消息和传输文件,实现的一个端到端的系统;与此同时,为了解决客户之间需要寻找陌生用户和与陌生用户建立通信的需求,我们搭建了一个服务器,供客户端访问服务端获得陌生人信息,服务器下发信息到客户端。客户端之间的通信我们使用的是面向无连接的UDP通信,而客户机与服务器之间的通信我们使用的是面向连接的TCP通信,建立的逻辑框图如下:
3、我们采用的开发语言是Java程序设计语言,其中用于实现UDP通 信的算法,如下所示:
如图所示,实现的是UDP的通信连接请求发送过程,标号1是我们实现的一个序列化类,用于存储需要发送的信息如文本,文件等等;标号2是通过InetAddress来设置需要连接的用户的IP地址,通过获得port来设置对方的软件端口,并通过socket发送出去,用户接受的程序实现如下:
其中通过获取输入流并解析就可以得到传输的内容。同理,基于TCP通信的发送请求和接受内容实现如下所示(以访问服务器为例):
我们采用的序列化发送类如下所示,其中Cmd是指自定义的一些识别代码,例如以1024代表的是发送文本,对方接受到内容并解析得到Cmd是1024后就知道要接受文本;还分别存储了己方账号和对方账号,便于双方知道通信双方的信息;其余变量类似,即存储文件或文件名以及存储发送的字节等等,最后一个向量存储的是访问服务器后得到的用户信息。
服务端因为要访问来自用户的访问,所以必须要实现多线程通信,所以我们加入了多线程编程(客户端也实现了),每个用户访问服务器都会启动一个线程来响应,线程体实现如下:
完成基本的框架搭建之后,为了增加系统的可视化性,增加了UI设计,提高用户使用体验感,便于用户直接使用;同时,由于系统需要存储用户信息避免再次返回系统时好友信息丢失,我们采用文件存储的方式来是实现数据持久化,即将用户(好友)数据保存于文件中,通过读写文件实现数据保存,实现效果如下含文件表:(以好友列表为例)
报文发送和文件处理部分示例代码,详情查看代码仓库:
package ht.ui;
//主窗口
import ht.bean.Account;
import ht.cmd.Cmd;
import ht.db.DBOper;
import ht_.Send;
import ht_.SendMsg;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Vector;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
//启动线程 进入循环等到接收消息
public class MainUI extends JFrame implements MouseListener,ActionListener{
/**
*
*/
private static final long serialVersionUID = 1L;
private Account account,friendAccount;
private JTabbedPane tab;
private JLabel lblhead;//登陆后显示的个人资料
private JList<?> lstFriend;
private JList<?> lstFamily;
private JList<?> lstclassmate;
private JList<?> lsthmd;
private JButton btnFind;//查找好友按钮
private Vector<Account> vFriend,vFamily,vClassmate,vHmd,vAllDetail;
private JPopupMenu pop;//弹出菜单
private JMenu menu;
private JMenuItem miChat,miLookInfo,miFriend,miFamily,miMate,miHmd,miDel;//聊天 查看资料 删除好友 移动好友
//创建哈希表保存所有在线用户的窗口
private LinkedHashMap<Integer,ChatUI> ht_ChatUsers;
public MainUI()
{
}
public MainUI(Account acc) throws IOException
{
this.account=acc;
setTitle(acc.getNickName());//设置窗口标签栏标题和头像
setIconImage(new ImageIcon(acc.getFace()).getImage());
//获取昵称 备注 QQ号 个性签名
String str="";
//备注不为空时,显示备注不显示昵称
if(!acc.getRemark().equals(""))
{
str=acc.getRemark()+"(";
}
//备注为空时,显示昵称
else {
str=acc.getNickName()+"(";
}
str+=acc.getQqCode()+")"+acc.getSelfsign();
lblhead=new JLabel(str,new ImageIcon(acc.getFace()),JLabel.LEFT);
add(lblhead,BorderLayout.NORTH);
vFriend=new Vector<Account>();
vFamily=new Vector<Account>();
vClassmate=new Vector<Account>();
vHmd=new Vector<Account>();
vAllDetail=new Vector<Account>();
lstFamily=new JList();
lstFriend=new JList();
lstclassmate=new JList();
lsthmd=new JList();
lstFriend.addMouseListener(this);
lstFamily.addMouseListener(this);
lstclassmate.addMouseListener(this);
lsthmd.addMouseListener(this);
refresh();//读好友列表
tab=new JTabbedPane();
tab.add("好友",new JScrollPane(lstFriend));
tab.add("家人",new JScrollPane(lstFamily));
tab.add("同学",new JScrollPane(lstclassmate));
tab.add("其他",new JScrollPane(lsthmd));
add(tab);
createMenu();
btnFind=new JButton("查找/添加好友");
add(btnFind,BorderLayout.SOUTH);
btnFind.addActionListener(this);
setSize(300,680);
setVisible(true);
setResizable(true);
//得到屏幕宽度,设置窗口位置
int width=Toolkit.getDefaultToolkit().getScreenSize().width-300;
setLocation(width,50);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//监听叉关闭
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
//super.windowClosing(e); //To change body of overridden methods use File | Settings | File Templates.
//这里写你想实现的代码,我只写了一行println
System.exit(0);
}
});
//启动消息接收线程
new ReceThread().start();
}
class listmodel extends AbstractListModel
{
Vector dats;
public listmodel(Vector dats)
{
this.dats=dats;
}
//获取行数
public Object getElementAt(int index)
{
Account user=(Account) dats.get(index);
return user.getNickName().trim()+"【"+user.getQqCode()+"】";
}
//获取长度
public int getSize()
{
return dats.size();
}
}
//获取好友头像
class myfind extends DefaultListCellRenderer
{
Vector datas;
public myfind(Vector datas)
{
this.datas=datas;
}
public Component getListCellRendererComponent(JList list,Object value, int index, boolean isSelected,boolean cellHasFocus)
{
Component c=super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus);
if(index >=0 && index<datas.size())
{
Account user=(Account) datas.get(index);
//根据列表中的好友在线状态设置头像
if(user.getStatus()==1)
{
setIcon(new ImageIcon(user.getFace()));
}
else
{
setIcon(new ImageIcon("face/bzx.png"));
}
setText(user.getNickName().trim()+"("+user.getQqCode()+")");
}
//设置字体颜色
if(isSelected)
{
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else
{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
return this;
}
}
//创建菜单
public void createMenu()
{
pop=new JPopupMenu();
miChat=new JMenuItem("聊天");
miLookInfo=new JMenuItem("查看资料");
miFriend=new JMenuItem("移动到好友");
miFamily=new JMenuItem("移动到家人");
miMate=new JMenuItem("移动到同学");
miHmd=new JMenuItem("移动到黑名单");
miDel=new JMenuItem("删除好友");
miChat.addActionListener(this);
miLookInfo.addActionListener(this);
miFriend.addActionListener(this);
miFamily.addActionListener(this);
miMate.addActionListener(this);
miHmd.addActionListener(this);
miDel.addActionListener(this);
pop.add(miChat);
pop.add(miLookInfo);
pop.add(miFriend);
pop.add(miFamily);
pop.add(miMate);
pop.add(miHmd);
pop.add(miDel);
}
//刷新界面
public void refresh() throws IOException
{
vAllDetail=new DBOper().getAllInfo(account);
//如果没有用户的情况下,直接结束函数
if(vAllDetail==null) {
//清楚之前所有的记录
vFriend.clear();
vFamily.clear();
vClassmate.clear();
vHmd.clear();
return;
}
//清楚之前所有的记录
vFriend.clear();
vFamily.clear();
vClassmate.clear();
vHmd.clear();
//把数据库的最新数据分别放到对应的向量
for(int i=0;i<vAllDetail.size();i++)
{
Account a=vAllDetail.get(i);
if(a.getGroupname().equals(Cmd.F_FRIEND))
{
vFriend.add(a);
}
else if(a.getGroupname().equals(Cmd.F_FAMILY))
{
vFamily.add(a);
}
else if(a.getGroupname().equals(Cmd.F_CLASSMATE))
{
vClassmate.add(a);
}
else if(a.getGroupname().equals(Cmd.F_HMD))
{
vHmd.add(a);
}
//暂时未做处理,直接显示在好友栏
vFriend.add(a);
}
//把向量放入List控件
lstFriend.setModel(new listmodel(vFriend));//显示资料
lstFriend.setCellRenderer(new myfind(vFriend));//显示头像
lstFamily.setModel(new listmodel(vFamily));//显示资料
lstFamily.setCellRenderer(new myfind(vFamily));//显示头像
lstclassmate.setModel(new listmodel(vClassmate));//显示资料
lstclassmate.setCellRenderer(new myfind(vClassmate));//显示头像
lsthmd.setModel(new listmodel(vHmd));//显示资料
lsthmd.setCellRenderer(new myfind(vHmd));//显示头像
}
@Override
public void mouseClicked(MouseEvent e) {
if(e.getSource()==lstFriend)
{
if(lstFriend.getSelectedIndex()==-1) {
JOptionPane.showMessageDialog(null, "当前列表无好友", "提示", JOptionPane.PLAIN_MESSAGE);
return;
}
friendAccount=(Account)vFriend.get(lstFriend.getSelectedIndex());
//双击
if(e.getClickCount()==2)
{
// new ChatUI(account,friendAccount);
findWin(friendAccount.getQqCode(),null);
}
//邮件
if(e.getButton()==3)
{
//好友被选中
if(lstFriend.getSelectedIndex()>=0)
{
pop.show(lstFriend, e.getX(), e.getY());
}
}
}
else if(e.getSource()==lstFamily)
{
if(lstFamily.getSelectedIndex()==-1) {
JOptionPane.showMessageDialog(null, "当前列表无好友", "提示", JOptionPane.PLAIN_MESSAGE);
return;
}
friendAccount=(Account)vFamily.get(lstFamily.getSelectedIndex());
//双击
if(e.getClickCount()==2)
{
//new ChatUI(account,friendAccount);
findWin(friendAccount.getQqCode(),null);
}
//邮件
if(e.getButton()==3)
{
//被选中
if(lstFamily.getSelectedIndex()>=0)
{
pop.show(lstFamily, e.getX(), e.getY());
}
}
}
else if(e.getSource()==lstclassmate)
{
if(lstclassmate.getSelectedIndex()==-1) {
JOptionPane.showMessageDialog(null, "当前列表无好友", "提示", JOptionPane.PLAIN_MESSAGE);
return;
}
friendAccount=(Account)vClassmate.get(lstclassmate.getSelectedIndex());
//双击
if(e.getClickCount()==2)
{
// new ChatUI(account,friendAccount);
findWin(friendAccount.getQqCode(),null);
}
//邮件
if(e.getButton()==3)
{
//被选中
if(lstclassmate.getSelectedIndex()>=0)
{
pop.show(lstclassmate, e.getX(), e.getY());
}
}
}
else if(e.getSource()==lsthmd)
{
if(lsthmd.getSelectedIndex()==-1) {
JOptionPane.showMessageDialog(null, "当前列表无好友", "提示", JOptionPane.PLAIN_MESSAGE);
return;
}
friendAccount=(Account)vHmd.get(lsthmd.getSelectedIndex());
//双击
if(e.getClickCount()==2)
{
//new ChatUI(account,friendAccount);
findWin(friendAccount.getQqCode(),null);
}
//右击
if(e.getButton()==3)
{
//被选中
if(lsthmd.getSelectedIndex()>=0)
{
pop.show(lsthmd, e.getX(), e.getY());
}
}
}
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btnFind)
{
try {
new FindUI(account);
} catch (IOException | ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if(e.getSource()==miChat)
{
// new ChatUI(account,friendAccount);
findWin(friendAccount.getQqCode(),null);
}
else if(e.getSource()==miLookInfo)
{
if(friendAccount!=null)
new LookUsers(friendAccount);
}
else if(e.getSource()==miDel)
{
try {
new DBOper().delFriend(account, friendAccount.getQqCode());
refresh();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
refresh();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if(e.getSource()==miFriend)
{
try {
new DBOper().moveFriend(account, friendAccount.getQqCode(),Cmd.F_FRIEND);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
refresh();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if(e.getSource()==miFamily)
{
try {
new DBOper().moveFriend(account, friendAccount.getQqCode(),Cmd.F_FAMILY);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
refresh();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if(e.getSource()==miMate)
{
try {
new DBOper().moveFriend(account, friendAccount.getQqCode(),Cmd.F_CLASSMATE);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
refresh();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if(e.getSource()==miHmd)
{
}
}
//接收消息的线程
class ReceThread extends Thread
{
public ReceThread()
{
//启动线程时 创建保存窗口的哈希表
ht_ChatUsers=new LinkedHashMap<Integer,ChatUI>();
}
public void run()
{
try
{
//自己端口接收数据
DatagramSocket serverSocket=new DatagramSocket(account.getPort());//在自己端口接收数据
//接收客户端发来的信息存入pack包
while(true)
{
byte b[]=new byte[1024*70];
DatagramPacket pack=new DatagramPacket(b,b.length) ;//数据包
serverSocket.receive(pack);
//把字节数组转换成SendMsg对象
//pack.getLength()接收到的字节数
ByteArrayInputStream bis=new ByteArrayInputStream(b,0,pack.getLength());//字节数组输入流
ObjectInputStream ois=new ObjectInputStream(bis);
SendMsg msg=(SendMsg)ois.readObject();
switch(msg.Cmd)
{
case Cmd.CMD_ONLINE://接收上线通知
refresh();
break;
case Cmd.CMD_OFFLINE://接收离线通知
refresh();
break;
case Cmd.CMD_CHAT://接收聊天信息
ChatUI chat=findWin(msg.selfAccount.getQqCode(),msg);//显示窗口
//获取聊天消息
chat.appendView(msg.selfAccount.getNickName(),msg.doc);
break;
case Cmd.CMD_DOUDONG://接收抖动信息
chat=findWin(msg.selfAccount.getQqCode(),msg);//显示窗口
chat.shake();
break;
case Cmd.CMD_ADDFRIEND://添加好友
String str=msg.selfAccount.getNickName()+"添加你为好友 ,请确认";
SendMsg m=new SendMsg();
m.friendAccount=msg.selfAccount;
m.selfAccount=msg.friendAccount;
//如果点击确定按钮就添加
if(JOptionPane.showConfirmDialog(null,str,"添加好友",JOptionPane.OK_CANCEL_OPTION)==JOptionPane.OK_OPTION)
{//往朋友表中添加记录
new DBOper().addFriend(m.friendAccount, m.selfAccount.getQqCode());
refresh();
m.Cmd=Cmd.CMD_AFREEFRIEND;
}else
{
m.Cmd=Cmd.CMD_REJECTFRIEND;
}
break;
case Cmd.CMD_AFREEFRIEND://同意
refresh();//刷新界面
break;
case Cmd.CMD_REJECTFRIEND://拒绝
JOptionPane.showMessageDialog(null,msg.selfAccount.getNickName()+"拒接了你的好友请求");
break;
case Cmd.CMD_FILESEND://接受文件
String str1=msg.selfAccount.getNickName()+"发送了文件"+msg.sFileName;
int cmd=Cmd.CMD_FILESUCC;
if(JOptionPane.showConfirmDialog(null,str1,"接收文件",JOptionPane.OK_CANCEL_OPTION)==JOptionPane.OK_OPTION)
{
FileDialog dlg=new FileDialog(MainUI.this,"保存",FileDialog.SAVE);
dlg.setFile(msg.sFileName);
dlg.show();
String sfilename=dlg.getDirectory()+"\\"+dlg.getFile();
File file=new File(sfilename);
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream fos=new FileOutputStream(sfilename);
fos.write(msg.b);
fos.close();
}else
{
cmd=Cmd.CMD_FILEFAILED;
}
SendMsg msg1=new SendMsg();
msg1.selfAccount=msg.friendAccount;
msg1.friendAccount=msg.selfAccount;
msg1.Cmd=cmd;
new Send().send(msg1);
break;
case Cmd.CMD_FILESUCC://回复接受成功
JOptionPane.showMessageDialog(null,msg.selfAccount.getNickName()+"接受了文件");
break;
case Cmd.CMD_FILEFAILED://回复拒接
JOptionPane.showMessageDialog(null,msg.selfAccount.getNickName()+"拒绝了文件");
break;
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//查找窗口是否存在,如果不存在则创建,存在则直接显示信息在界面
public ChatUI findWin(Integer qqcode,SendMsg msg)
{
ChatUI chat=null;
//查找窗口是否存在
chat =ht_ChatUsers.get(qqcode);
if(chat==null)//不存在则创建聊天窗口
{
if(msg==null)//双击或者右键打开窗口
{
chat=new ChatUI(account,friendAccount);
}else//线程打开窗口
{
chat=new ChatUI(msg.friendAccount,msg.selfAccount);
}
//窗口加入哈希表
ht_ChatUsers.put(qqcode,chat);
}
if(!chat.isVisible())
{
chat.show();
}
return chat;
}
//修改用户状态
public void UpdateStatus(Account acc) throws IOException
{
int size=vAllDetail.size();
for(int i=0;i<size;i++)
{
Account a=vAllDetail.get(i);
if(a.getQqCode()==acc.getQqCode())
{
a.setStatus(acc.getStatus());
vAllDetail.set(i, a);
break;
}
}
refresh();
}
}
package ht.db;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;
import javax.swing.JOptionPane;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import ht.bean.Account;
import ht.cmd.Cmd;
//进行数据库操作的函数
public class DBOper {
//所有值都放到account对象里去了 ,传一个Account对象过来,注册用户的函数
public boolean addUser(Account acc) throws IOException
{
boolean bok=false;
HSSFWorkbook conn=new DBConn().getWrokbook();
for (int sh=0;sh<2;sh++) {
HSSFSheet sheet=conn.getSheetAt(sh);
int index=sheet.getLastRowNum();
HSSFRow row = sheet.getRow(index);
if(row != null) {//检查行是不是空
index+=1;
}
try {
HSSFRow currow = sheet.createRow((short)index);
HSSFCellStyle textStyle = conn.createCellStyle();
HSSFDataFormat format = conn.createDataFormat();
// textStyle.setDataFormat(format.getFormat("@"));
// cell.setCellStyle(textStyle);//设置单元格格式为"文本"
// cell.setCellType(HSSFCell.CELL_TYPE_STRING);
HSSFCell cell=null;
//在row里建立新cell(单元格),参数为列号(第一列) //设置cell的整数类型的值
cell=currow.createCell(0);
cell.setCellValue(String.valueOf(acc.getQqCode())); //设置cell浮点类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(1);
cell.setCellValue(String.valueOf(acc.getNickName())); //设置cell字符类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(2);
cell.setCellValue(String.valueOf(acc.getPwd())); //设置cell布尔类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(3);
cell.setCellValue(String.valueOf(acc.getIpAddr())); //设置cell浮点类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(4);
cell.setCellValue(String.valueOf(acc.getPort())); //设置cell字符类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(5);
cell.setCellValue(String.valueOf(acc.getAge())); //设置cell布尔类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(6);
cell.setCellValue(String.valueOf(acc.getSex())); //设置cell浮点类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(7);
cell.setCellValue(String.valueOf(acc.getNation())); //设置cell字符类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(8);
cell.setCellValue(String.valueOf(acc.getStar())); //设置cell布尔类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(9);
if(String.valueOf(acc.getFace()).equals("")) {
cell.setCellValue("face\3.jpg");
}
else {
cell.setCellValue(String.valueOf(acc.getFace())); //设置cell浮点类型的值
}
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(10);
cell.setCellValue(String.valueOf(acc.getRemark())); //设置cell字符类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(11);
cell.setCellValue(String.valueOf(acc.getSelfsign())); //设置cell布尔类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell=currow.createCell(12);
cell.setCellValue(String.valueOf(acc.getStatus())); //设置cell布尔类型的值
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
FileOutputStream fileOut = new FileOutputStream("data.xls");
conn.write(fileOut);
fileOut.close();
//状态
bok=true;
}
catch(Exception e){
e.printStackTrace();
}
}
return bok;
}
//判断端口是否已经被占用
public boolean isPort(int port) throws IOException
{
boolean bok=false;
HSSFWorkbook conn=new DBConn().getWrokbook();
try {
for (int i=0;i<3;i++) {
HSSFSheet sheet=conn.getSheetAt(i);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {//第一行是空就代表没有数据了,更不能用getCell了
// return false;
continue;
}
for (int j=0;j<=num;j++) {
HSSFRow row = sheet.getRow(j);
if(String.valueOf(port).equals(String.valueOf(row.getCell(4).getStringCellValue()))) {
return true;
}
}
}
}catch(Exception e)
{
e.printStackTrace();
}
return bok;
}
//登录函数,返回account对象
public Account login(Account acc) throws IOException
{
HSSFWorkbook conn=new DBConn().getWrokbook();
try {
boolean flag1=false;
int index=-1;
HSSFSheet sheet=conn.getSheetAt(0);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {
return null;
}
for (int j=0;j<=num;j++) {
HSSFRow row = sheet.getRow(j);
if(String.valueOf(acc.getQqCode()).equals(String.valueOf(row.getCell(0).getStringCellValue()))
&& String.valueOf(acc.getPwd()).equals(String.valueOf(row.getCell(2).getStringCellValue()))) {
flag1=true;
index=j;
break;
}
}
//ResultSet表示从数据库中查询到的返回结果
if(flag1)//查到了账号名跟密码匹配的东西 已经登陆了
{ //登陆成功,读取用户所有信息
//修改状态为在线(1)
HSSFRow row = sheet.getRow(index);
acc.setNickName(String.valueOf(row.getCell(1).getStringCellValue()));
acc.setIpAddr(String.valueOf(row.getCell(3).getStringCellValue()));
acc.setPort(Integer.parseInt(String.valueOf(row.getCell(4).getStringCellValue())));
acc.setAge(Integer.parseInt(String.valueOf(row.getCell(5).getStringCellValue())));
acc.setSex(String.valueOf(row.getCell(6).getStringCellValue()));
acc.setNation(String.valueOf(row.getCell(7).getStringCellValue()));
acc.setStar(String.valueOf(row.getCell(8).getStringCellValue()));
acc.setFace(String.valueOf(row.getCell(9).getStringCellValue()));
acc.setRemark(String.valueOf(row.getCell(10).getStringCellValue()));
acc.setSelfsign(String.valueOf(row.getCell(11).getStringCellValue()));
acc.setStatus(1);//修改对象值为1
//修改数据库中存储状态为上线
modifyStatus(acc.getQqCode(),1);
}
}catch(Exception e)
{
e.printStackTrace();
}
return acc;
}
//查找个人资料
public Account findByQQcode (int qqcode) throws IOException{
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {
return null;
}
Account acc=new Account();
try {
int index=-1;
boolean flag2=false;
for(int i=1;i<=num;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(qqcode).equals(String.valueOf(row.getCell(0).getStringCellValue()))) {
index=i;
flag2=true;
break;
}
}
if(flag2)//查到了账号名跟密码匹配的东西 已经登陆了
{ //登陆成功,读取用户所有信息
HSSFRow row = sheet.getRow(index);
acc.setQqCode(qqcode);
acc.setNickName(String.valueOf(row.getCell(1).getStringCellValue()));
acc.setIpAddr(String.valueOf(row.getCell(3).getStringCellValue()));
acc.setPort(Integer.parseInt(String.valueOf(row.getCell(4).getStringCellValue())));
acc.setAge(Integer.parseInt(String.valueOf(row.getCell(5).getStringCellValue())));
acc.setSex(String.valueOf(row.getCell(6).getStringCellValue()));
acc.setNation(String.valueOf(row.getCell(7).getStringCellValue()));
acc.setStar(String.valueOf(row.getCell(8).getStringCellValue()));
acc.setFace(String.valueOf(row.getCell(9).getStringCellValue()));
acc.setRemark(String.valueOf(row.getCell(10).getStringCellValue()));
acc.setSelfsign(String.valueOf(row.getCell(11).getStringCellValue()));
}
}catch(Exception e)
{
e.printStackTrace();
}
return acc;
}
public boolean modifyStatus(int qqcode,int status) throws IOException
{
boolean bok=false;
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {
return false;
}
try {
int index=-1;
boolean flag3=false;
for(int i=1;i<=num;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(qqcode).equals(String.valueOf(row.getCell(0).getStringCellValue()))){
index=i;
flag3=true;
break;
}
}
if(flag3) {
HSSFRow row = sheet.getRow(index);
String NickName=(String.valueOf(row.getCell(1).getStringCellValue()));
String pwd=(String.valueOf(row.getCell(2).getStringCellValue()));
String IpAddr=(String.valueOf(row.getCell(3).getStringCellValue()));
String Port=(String.valueOf(row.getCell(4).getStringCellValue()));
String Age=(String.valueOf(row.getCell(5).getStringCellValue()));
String Sex=(String.valueOf(row.getCell(6).getStringCellValue()));
String Nation=(String.valueOf(row.getCell(7).getStringCellValue()));
String Star=(String.valueOf(row.getCell(8).getStringCellValue()));
String Face=(String.valueOf(row.getCell(9).getStringCellValue()));
String Remark=(String.valueOf(row.getCell(10).getStringCellValue()));
String Selfsign=(String.valueOf(row.getCell(11).getStringCellValue()));
HSSFRow currow = sheet.createRow((short)index);
//在row里建立新cell(单元格),参数为列号(第一列) //设置cell的整数类型的值
currow.createCell(0).setCellValue(String.valueOf(qqcode)); //设置cell浮点类型的值
currow.createCell(1).setCellValue(String.valueOf(NickName)); //设置cell字符类型的值
currow.createCell(2).setCellValue(String.valueOf(pwd)); //设置cell布尔类型的值
currow.createCell(3).setCellValue(String.valueOf(IpAddr)); //设置cell浮点类型的值
currow.createCell(4).setCellValue(String.valueOf(Port)); //设置cell字符类型的值
currow.createCell(5).setCellValue(String.valueOf(Age)); //设置cell布尔类型的值
currow.createCell(6).setCellValue(String.valueOf(Sex)); //设置cell浮点类型的值
currow.createCell(7).setCellValue(String.valueOf(Nation)); //设置cell字符类型的值
currow.createCell(8).setCellValue(String.valueOf(Star)); //设置cell布尔类型的值
currow.createCell(9).setCellValue(String.valueOf(Face)); //设置cell浮点类型的值
currow.createCell(10).setCellValue(String.valueOf(Remark)); //设置cell字符类型的值
currow.createCell(11).setCellValue(String.valueOf(Selfsign)); //设置cell布尔类型的值
currow.createCell(12).setCellValue(String.valueOf(status)); //设置cell布尔类型的值
FileOutputStream fileOut = new FileOutputStream("data.xls");
conn.write(fileOut);
fileOut.close();
bok=true;
}
}catch(Exception e)
{
e.printStackTrace();
}
return bok;
}
//返回头像
public String getFace(int qqcode) throws IOException
{
String face="";
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int num=sheet.getLastRowNum();
if(sheet.getRow(num)==null) {
return "face\1.jpg";
}
// Account acc=new Account();
try {
int index=-1;
boolean flag4=false;
for(int i=1;i<=num;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(qqcode).equals(String.valueOf(row.getCell(0).getStringCellValue()))) {
index=i;
flag4=true;
break;
}
}
if(flag4) {
HSSFRow row = sheet.getRow(index);
face=String.valueOf(row.getCell(9).getStringCellValue());
}
}catch(Exception e)
{
e.printStackTrace();
}
return face;
}
//返回所有好友,家人,同学,黑名单等资料
public Vector<Account> getAllInfo(Account acc1) throws IOException
{
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {
return null;
}
Vector<Account> allInfo=new Vector<Account>();
try {
for (int index=0;index<=num;index++) {
Account acc=new Account();//一条记录创建一个Account对象
HSSFRow row = sheet.getRow(index);
acc.setQqCode(Integer.parseInt(String.valueOf(row.getCell(0).getStringCellValue())));
acc.setNickName(String.valueOf(row.getCell(1).getStringCellValue()));
acc.setIpAddr(String.valueOf(row.getCell(3).getStringCellValue()));
acc.setPort(Integer.parseInt(String.valueOf(row.getCell(4).getStringCellValue())));
acc.setAge(Integer.parseInt(String.valueOf(row.getCell(5).getStringCellValue())));
acc.setSex(String.valueOf(row.getCell(6).getStringCellValue()));
acc.setNation(String.valueOf(row.getCell(7).getStringCellValue()));
acc.setStar(String.valueOf(row.getCell(8).getStringCellValue()));
acc.setFace(String.valueOf(row.getCell(9).getStringCellValue()));
acc.setRemark(String.valueOf(row.getCell(10).getStringCellValue()));
acc.setSelfsign(String.valueOf(row.getCell(11).getStringCellValue()));
acc.setStatus(Integer.parseInt(String.valueOf(row.getCell(12).getStringCellValue())));
acc.setGroupname("myQQFriends");
allInfo.add(acc);
}
}catch(Exception e)
{
e.printStackTrace();
}
return allInfo;
}
//查找好友
public Vector<Vector<String>> find(Account acc1) throws IOException
{
HSSFWorkbook conn=new DBConn().getWrokbook();
// Vector<Account> allInfo=new Vector<Account>();
Vector<Vector<String>> allInfo=new Vector<Vector<String>>();
HSSFSheet sheet=conn.getSheetAt(0);
int num=sheet.getLastRowNum();
if(sheet.getRow(0)==null) {
return allInfo;
}
try {
int index=-1;
boolean flag5=false;
for(int i=0;i<=num;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(acc1.getQqCode()).equals(String.valueOf(row.getCell(0).getStringCellValue()))){
index=i;
flag5=true;
break;
}
}
if(flag5) {
Vector<String> a=new Vector<String>();
// Account acc=new Account();
//a.addElement(Integer.parseInt(String.valueOf(sheet.getCell(index,0))));
HSSFRow row = sheet.getRow(index);
a.addElement(String.valueOf(row.getCell(0).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(1).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(3).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(4).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(5).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(6).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(7).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(8).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(9).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(10).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(11).getStringCellValue()));
a.addElement(String.valueOf(row.getCell(12).getStringCellValue()));
a.addElement("myQQFriends");
allInfo.add(a);
}
//取出朋友的信息,在线状态,以及分组
}catch(Exception e)
{
e.printStackTrace();
}
return allInfo;
}
//添加好友
public boolean addFriend(Account acc,int friendcode) throws IOException
{
// System.out.println(acc.getQqCode()+" "+friendcode);
boolean bok=false;
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int num=sheet.getLastRowNum();
if(sheet.getRow(num)!=null) {
num+=1;
}
try {
//添加好友
HSSFRow currow = sheet.createRow((short)num);
//在row里建立新cell(单元格),参数为列号(第一列) //设置cell的整数类型的值
currow.createCell(0).setCellValue(String.valueOf(acc.getQqCode())); //设置cell浮点类型的值
currow.createCell(1).setCellValue(String.valueOf(acc.getNickName())); //设置cell字符类型的值
currow.createCell(3).setCellValue(String.valueOf(acc.getIpAddr())); //设置cell浮点类型的值
currow.createCell(4).setCellValue(String.valueOf(acc.getPort())); //设置cell字符类型的值
currow.createCell(5).setCellValue(String.valueOf(acc.getAge())); //设置cell布尔类型的值
currow.createCell(6).setCellValue(String.valueOf(acc.getSex())); //设置cell浮点类型的值
currow.createCell(7).setCellValue(String.valueOf(acc.getNation())); //设置cell字符类型的值
currow.createCell(8).setCellValue(String.valueOf(acc.getStar())); //设置cell布尔类型的值
currow.createCell(9).setCellValue(String.valueOf(acc.getFace())); //设置cell浮点类型的值
currow.createCell(10).setCellValue(String.valueOf(acc.getRemark())); //设置cell字符类型的值
currow.createCell(11).setCellValue(String.valueOf(acc.getSelfsign())); //设置cell布尔类型的值
currow.createCell(12).setCellValue(String.valueOf(acc.getStatus())); //设置cell布尔类型的值
FileOutputStream fileOut = new FileOutputStream("data.xls");
conn.write(fileOut);
fileOut.close();
//互相添加?
//状态
bok=true;
}catch(Exception e)
{
e.printStackTrace();
}
return bok;
}
//删除好友
public boolean delFriend(Account acc,int friendcode) throws IOException
{
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
FileOutputStream fileOut=null;
int num=sheet.getLastRowNum();
if(sheet.getRow(num)==null) {
return false;
}
try {
int index=-1;
boolean flag6=false;
for(int i=0;i<num;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(friendcode).equals(String.valueOf(row.getCell(0).getStringCellValue()))) {
index=i;
flag6=true;
break;
}
}
if(flag6) {
//逐步上移
for(int i=index;i<num;i++) {
HSSFRow row = sheet.getRow(i+1);
String qqcode=(String.valueOf(row.getCell(0).getStringCellValue()));
String NickName=(String.valueOf(row.getCell(1).getStringCellValue()));
String pwd=(String.valueOf(row.getCell(2).getStringCellValue()));
String IpAddr=(String.valueOf(row.getCell(3).getStringCellValue()));
String Port=(String.valueOf(row.getCell(4).getStringCellValue()));
String Age=(String.valueOf(row.getCell(5).getStringCellValue()));
String Sex=(String.valueOf(row.getCell(6).getStringCellValue()));
String Nation=(String.valueOf(row.getCell(7).getStringCellValue()));
String Star=(String.valueOf(row.getCell(8).getStringCellValue()));
String Face=(String.valueOf(row.getCell(9).getStringCellValue()));
String Remark=(String.valueOf(row.getCell(10).getStringCellValue()));
String Selfsign=(String.valueOf(row.getCell(11).getStringCellValue()));
String Status=(String.valueOf(row.getCell(12).getStringCellValue()));
HSSFRow currow = sheet.createRow((short)i);
//在row里建立新cell(单元格),参数为列号(第一列) //设置cell的整数类型的值
currow.createCell(0).setCellValue(String.valueOf(qqcode)); //设置cell浮点类型的值
currow.createCell(1).setCellValue(String.valueOf(NickName)); //设置cell字符类型的值
currow.createCell(2).setCellValue(String.valueOf(pwd)); //设置cell布尔类型的值
currow.createCell(3).setCellValue(String.valueOf(IpAddr)); //设置cell浮点类型的值
currow.createCell(4).setCellValue(String.valueOf(Port)); //设置cell字符类型的值
currow.createCell(5).setCellValue(String.valueOf(Age)); //设置cell布尔类型的值
currow.createCell(6).setCellValue(String.valueOf(Sex)); //设置cell浮点类型的值
currow.createCell(7).setCellValue(String.valueOf(Nation)); //设置cell字符类型的值
currow.createCell(8).setCellValue(String.valueOf(Star)); //设置cell布尔类型的值
currow.createCell(9).setCellValue(String.valueOf(Face)); //设置cell浮点类型的值
currow.createCell(10).setCellValue(String.valueOf(Remark)); //设置cell字符类型的值
currow.createCell(11).setCellValue(String.valueOf(Selfsign)); //设置cell布尔类型的值
currow.createCell(12).setCellValue(String.valueOf(Status)); //设置cell布尔类型的值
fileOut = new FileOutputStream("data.xls");
// conn.write(fileOut);
// fileOut.close();
}
// sheet.createRow((short)num);//最后一行置空
sheet.removeRow(sheet.getRow(num));
conn.write(fileOut);
fileOut.close();
}
JOptionPane.showMessageDialog(null, "已将好友从数据库删除", "提示", JOptionPane.PLAIN_MESSAGE);
}catch(Exception e)
{
e.printStackTrace();
}
return true;
}
//移动好友
public boolean moveFriend(Account acc,int friendcode,String groupname) throws IOException
{
HSSFWorkbook conn=new DBConn().getWrokbook();
HSSFSheet sheet=conn.getSheetAt(1);
int number=0;
int num=sheet.getLastRowNum();
if(sheet.getRow(num)==null) {
return false;
}
try {
int index=-1;
boolean flag7=false;
for(int i=0;i<=number;i++) {
HSSFRow row = sheet.getRow(i);
if(String.valueOf(acc.getQqCode()).equals(String.valueOf(row.getCell(0).getStringCellValue()))) {
index=i;
flag7=true;
break;
}
}
if(flag7) {
HSSFRow row = sheet.getRow(index);
String qqcode=(String.valueOf(row.getCell(0).getStringCellValue()));
String NickName=(String.valueOf(row.getCell(1).getStringCellValue()));
String pwd=(String.valueOf(row.getCell(2).getStringCellValue()));
String IpAddr=(String.valueOf(row.getCell(3).getStringCellValue()));
String Port=(String.valueOf(row.getCell(4).getStringCellValue()));
String Age=(String.valueOf(row.getCell(5).getStringCellValue()));
String Sex=(String.valueOf(row.getCell(6).getStringCellValue()));
String Nation=(String.valueOf(row.getCell(7).getStringCellValue()));
String Star=(String.valueOf(row.getCell(8).getStringCellValue()));
String Face=(String.valueOf(row.getCell(9).getStringCellValue()));
String Remark=(String.valueOf(row.getCell(10).getStringCellValue()));
String Selfsign=(String.valueOf(row.getCell(11).getStringCellValue()));
String Status=(String.valueOf(row.getCell(12).getStringCellValue()));
HSSFRow currow = sheet.createRow((short)index);
//在row里建立新cell(单元格),参数为列号(第一列) //设置cell的整数类型的值
currow.createCell(0).setCellValue(String.valueOf(qqcode)); //设置cell浮点类型的值
currow.createCell(1).setCellValue(String.valueOf(NickName)); //设置cell字符类型的值
currow.createCell(2).setCellValue(String.valueOf(pwd)); //设置cell布尔类型的值
currow.createCell(3).setCellValue(String.valueOf(IpAddr)); //设置cell浮点类型的值
currow.createCell(4).setCellValue(String.valueOf(Port)); //设置cell字符类型的值
currow.createCell(5).setCellValue(String.valueOf(Age)); //设置cell布尔类型的值
currow.createCell(6).setCellValue(String.valueOf(Sex)); //设置cell浮点类型的值
currow.createCell(7).setCellValue(String.valueOf(Nation)); //设置cell字符类型的值
currow.createCell(8).setCellValue(String.valueOf(Star)); //设置cell布尔类型的值
currow.createCell(9).setCellValue(String.valueOf(Face)); //设置cell浮点类型的值
currow.createCell(10).setCellValue(String.valueOf(Remark)); //设置cell字符类型的值
currow.createCell(11).setCellValue(String.valueOf(Selfsign)); //设置cell布尔类型的值
currow.createCell(12).setCellValue(String.valueOf(Status)); //设置cell布尔类型的值
currow.createCell(113).setCellValue("myFriends");
FileOutputStream fileOut = new FileOutputStream("data.xls");
conn.write(fileOut);
fileOut.close();
}
}catch(Exception e)
{
e.printStackTrace();
}
return true;
}
}
|