题目出自2020年夏季学期,CAU2019级理科试验班,《农业信息化应用开发实训I》课程结课作业。名曰农业信息化开发实训,实则与农业毫无联系,只是一门Java课程。
笔者对此项目的论述绝对不是标准答案,也不是最好的解答,甚至不能算的上优秀,因为笔者最终只在本门课程拿了A-的成绩。但这并不意味着这篇文章毫无意义。一来本文中的部分手段可以为后辈借鉴,二来如果您需要获得A或者A+的成绩,您完全有必要比笔者的程序做的更加出色。
如果您需要笔者完整的源代码,可以查看笔者上传的资源https://download.csdn.net/download/qq_45681057/12910173
如果您对笔者的程序有什么看法建议或者疑问,都可以私信笔者:[email protected]。或者直接在文章下面评论(或者认识我的人直接通过微信qq联系我,可以和我交流各种事情\偷笑)。笔者可能有时比较繁忙,回复不太及时,请见谅。
开发一个小型的宿舍文件仓储系统。系统包括文件存储服务器和用户客户端两部分,见下图。
文件服务器:
响应客户端请求,提供由客户端指定文件操作。主要有:
等。
客户端:
向服务请求文件上传,下载等存储操作。
要求:
(1)网络通讯用Java Socket实现。
(2)必须实现题目要求的功能,具体操作和功能可自行确定。
(3)程序必须有GUI界面,具体界面可自行设计。
实践题目除了完成程序设计(程序编写)外还需要提供软件设计文档,有关软件设计文档的内容包括:
笔者先给出源代码部分,再给出论文部分。
其中源代码部分主要包含两大板块,其一为客户端,其二为服务器。其中客户端只有一个名为2020_Final_Project的包,而服务器则有六个,分别为Server_delete,Server_download,Server_rename,Server_test,Server_tree,Server_upload。
(1) test1.java(登录界面,涉及GUI)
package Final_Project;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
class Login extends JFrame {
JPanel panel0 = new JPanel();
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
JLabel jlb0 = new JLabel("903网盘:乐在分享");
JLabel jlb1 = new JLabel("账号:");
JTextField txt1 = new JTextField(25);
JLabel jlb2 = new JLabel("密码:");
JPasswordField txt2 = new JPasswordField(25);
JButton btn1 = new JButton("登录");
client_test db_exam;
Login(String s) {
db_exam = new client_test();
setSize(400, 215);
setVisible(true);
setTitle(s);
setResizable(false);
setLayout(new FlowLayout());
Font font1 = new Font("", Font.PLAIN, 25);
Dimension preferredSize1 = new Dimension(320, 30);
Dimension preferredSize2 = new Dimension(400, 45);
panel0.setPreferredSize(preferredSize2);
jlb0.setFont(font1);
panel0.setBackground(Color.darkGray);
jlb0.setForeground(Color.orange);
panel0.add(jlb0);
add(panel0);
btn1.setPreferredSize(preferredSize1);
panel1.add(jlb1);
panel1.add(txt1);
add(panel1);
panel2.add(jlb2);
panel2.add(txt2);
add(panel2);
panel3.add(btn1);
add(panel3);
db_exam.setExam_id(txt1);
db_exam.setExam_pw(txt2);
btn1.addActionListener(db_exam);
btn1.setMnemonic(KeyEvent.VK_ENTER);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
validate();
}
}
public class test1 {
public static void main(String[] args){
Login login = new Login("903网盘");
}
}
(2) Management.java(文件管理界面,涉及GUI)
package Final_Project;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.io.IOException;
import java.util.Hashtable;
public class Management extends JFrame implements TreeSelectionListener{
JTree tree;
JFrame f = new JFrame();
JPanel panel5 = new JPanel();
Dimension preferredSize3 = new Dimension(50,200);
Dimension preferredSize4 = new Dimension(170, 40);
JButton jbt_upload = new JButton("上传文件");
JButton jbt_download = new JButton("下载文件");
JButton jbt_delete = new JButton("删除文件");
JButton jbt_rename = new JButton("文件重命名");
String[] s1 = {
"_init_"};
String[] s2 = {
"_init_"};
jbt_up jbtUp = new jbt_up();
jbt_down jbtDown = new jbt_down();
jbt_del jbtDel = new jbt_del();
jbt_re jbtRe = new jbt_re();
String ID;
Hashtable hashtable1;
Hashtable hashtable2;
client_tree clientTree = null;
public void setID1(String id){
ID = new String(id);System.out.println("成功设置tree的id");}
public void connection() throws IOException {
clientTree = new client_tree();
clientTree.setID4(ID);
clientTree.connection();
s1 = clientTree.trees1_1;
s2 = clientTree.trees1_2;
hashtable2.put("共享文件",s2);
hashtable2.put("个人文件",s1);
hashtable1.put("903网盘",hashtable2);
}
Management() throws IOException {
jbt_upload.setPreferredSize(preferredSize4);
jbt_download.setPreferredSize(preferredSize4);
jbt_delete.setPreferredSize(preferredSize4);
jbt_rename.setPreferredSize(preferredSize4);
jbt_upload.setEnabled(false);
jbt_download.setEnabled(false);
jbt_delete.setEnabled(false);
jbt_rename.setEnabled(false);
panel5.setPreferredSize(preferredSize3);
panel5.setLayout(new FlowLayout());
panel5.add(jbt_upload);
panel5.add(jbt_download);
panel5.add(jbt_delete);
panel5.add(jbt_rename);
hashtable1 = new Hashtable();
hashtable2 = new Hashtable();
hashtable1.put("903网盘",hashtable2);
hashtable2.put("共享文件",s2);
hashtable2.put("个人文件",s1);
tree = new JTree(hashtable1);
JScrollPane scroll = new JScrollPane();
scroll.setViewportView(tree);
Container con = f.getContentPane();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,scroll,panel5);
splitPane.setDividerLocation(0.5);
con.add(splitPane);
tree.addTreeSelectionListener(this);
jbt_upload.addActionListener(jbtUp);
jbt_download.addActionListener(jbtDown);
jbt_delete.addActionListener(jbtDel);
jbt_rename.addActionListener(jbtRe);
f.setResizable(false);
f.setSize(300,225);
f.setVisible(true);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
public void valueChanged(TreeSelectionEvent e){
if(e.getSource() == tree){
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
String str = node.toString();
String strr = node.getParent().toString();
if(str.equals("903网盘")){
jbt_upload.setEnabled(false);
jbt_download.setEnabled(false);
jbt_delete.setEnabled(false);
jbt_rename.setEnabled(false);
}
else if(str.equals("个人文件")){
jbtUp.setID2(ID);
jbt_upload.setEnabled(true);
jbt_download.setEnabled(false);
jbt_delete.setEnabled(false);
jbt_rename.setEnabled(false);
}
else if(str.equals("共享文件")){
jbtUp.setID2("903");
jbt_upload.setEnabled(true);
jbt_download.setEnabled(false);
jbt_delete.setEnabled(false);
jbt_rename.setEnabled(false);
}
else{
if(strr.equals("共享文件"))
{
jbtDel.ID = "903";
jbtRe.ID = "903";
jbtDown.ID = "903";
}
else {
jbtDel.ID = ID;
jbtRe.ID = ID;
jbtDown.ID = ID;
}
jbtDel.setName(str);
jbtRe.setName(str);
jbtDown.setName(str);
jbt_upload.setEnabled(false);
jbt_download.setEnabled(true);
jbt_delete.setEnabled(true);
jbt_rename.setEnabled(true);
}
}
}
public static void main(String[] args) throws IOException {
new Management();
}
}
(3) jbt_up.java(上传按钮,涉及GUI)
package Final_Project;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class jbt_up extends JFrame implements ActionListener {
JPanel p = new JPanel();
JLabel lb = new JLabel("文件路径:");
JTextField txt = new JTextField(30);
JButton btn = new JButton("开始上传");
client_upload client = new client_upload();
String ID;
public void setID2(String id){
ID = new String(id);
System.out.println("ID in jbt_up is "+ID);}
public void actionPerformed(ActionEvent e) {
setTitle("Upload");
setSize(450,120);
setVisible(true);
setLayout(new FlowLayout());
setResizable(false);
p.add(lb);
p.add(txt);
add(p);
add(btn);
client.setStr(txt);
client.setID3(ID);
btn.addActionListener(client);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
validate();
}
}
(4) jbt_re.java(重命名按钮,涉及GUI)
package Final_Project;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class jbt_re extends JFrame implements ActionListener {
JPanel p = new JPanel();
JLabel lb = new JLabel("重命名为:");
JTextField txt = new JTextField(10);
JButton btn = new JButton("确认");
client_rename clientRename = new client_rename();
String s;
String ID;
public void setName(String ss){
s = ss;
}
public void actionPerformed(ActionEvent e) {
setTitle("Rename");
setSize(260,110);
setVisible(true);
setLayout(new FlowLayout());
setResizable(false);
p.add(lb);
p.add(txt);
add(p);
add(btn);
clientRename.setStr(txt);
clientRename.setID6(ID);
clientRename.setName(s);
btn.addActionListener(clientRename);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
validate();
}
}
(5) jbt_down.java(重命名按钮,涉及GUI)
package Final_Project;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class jbt_down extends JFrame implements ActionListener {
JPanel p = new JPanel();
JLabel lb = new JLabel("下载路径:");
JTextField txt = new JTextField(30);
JButton btn = new JButton("开始下载");
client_download clientDownload = new client_download();
String s;
String ID;
public void setName(String ss){
s = ss;
}
public void actionPerformed(ActionEvent e){
setTitle("Download");
setSize(450,120);
setVisible(true);
setResizable(false);
setLocationRelativeTo(null);
setLayout(new FlowLayout());
p.add(lb);
p.add(txt);
add(p);
add(btn);
btn.addActionListener(clientDownload);
clientDownload.setID7(ID);
clientDownload.setName(s);
clientDownload.setStr(txt);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
validate();
}
}
(6) jbt_del.java(删除按钮,涉及GUI)
package Final_Project;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class jbt_del extends JFrame implements ActionListener {
JLabel lb = new JLabel("确定要删除吗?");
JButton jbt = new JButton("确认");
Panel p = new Panel();
client_del clientDel = new client_del();
String s;
String ID;
public void setName(String ss){
s = ss;
}
public void actionPerformed(ActionEvent e) {
System.out.println("所需删除文件属于"+ID);
setTitle("Warning");
setSize(150,110);
p.setSize(150,50);
setVisible(true);
setLayout(new FlowLayout());
setResizable(false);
p.add(lb);
add(p);
add(jbt);
clientDel.setName(s);
clientDel.setID5(ID);
jbt.addActionListener(clientDel);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
validate();
}
}
(7) client_test.java(登录验证客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
public class client_test implements ActionListener {
JTextField exam_id;
JPasswordField exam_pw;
Socket socket;
int flag = 0;
OutputStream out;
public void setExam_id(JTextField a) {
exam_id = a;
}
public void setExam_pw(JPasswordField a) {
exam_pw = a;
}
public void actionPerformed(ActionEvent e) {
if (exam_id.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先输入账号~");
} else if (exam_pw.getText().equals("")) {
JOptionPane.showMessageDialog(null, "密码不能为空哦~");
} else {
try {
examine_login();
} catch (IOException ioException) {
ioException.printStackTrace();
}
if (flag == 1) {
System.out.println("登录成功!");
Management mng = null;
try {
mng = new Management();
} catch (IOException ioException) {
ioException.printStackTrace();
}
mng.setID1(exam_id.getText());
try {
mng.connection();
} catch (IOException ioException) {
ioException.printStackTrace();
}
flag = 0;
} else {
System.out.println("登录失败!");
JOptionPane.showMessageDialog(null, "登录信息有误,请重新输入!");
exam_pw.setText("");
}
}
}
public void examine_login() throws IOException {
try {
socket = new Socket("localhost", 10004);
} catch (IOException e) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
String namePwd = exam_id.getText()+","+exam_pw.getText();
out = socket.getOutputStream();
out.write(namePwd.getBytes());
System.out.println("正在验证...");
flag = socket.getInputStream().read();
socket.close();
}
}
(8) client_tree.java(获取管理界面文件信息客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class client_tree {
Socket socket;
String ID;
OutputStream out;
InputStream in;
String trees;
String[] trees1;
String[] trees1_1 = null;
String[] trees1_2 = null;
public void setID4(String id){
ID = new String(id);}
client_tree() {
}
public void connection() throws IOException {
try {
socket = new Socket("localhost", 8888);
} catch (IOException e) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
out = socket.getOutputStream();
System.out.println(ID);
out.write(ID.getBytes());
System.out.println("重新规划树...");
in = socket.getInputStream();
byte[] buf = new byte[65560];
int len = in.read(buf);
trees = new String(buf,0,len);
trees = trees.substring(0, trees.length() - 1);
trees1 = trees.split(",",-1);
int k;
int i=0;
for(;i<trees1.length;i++){
if(trees1[i].equals("903"))
break;
}
trees1_1 = new String[i];
for(k = 0;k<i;k++){
trees1_1[k]=trees1[k];
}
i++;
trees1_2 = new String[trees1.length-i];
for(k = 0;i<trees1.length;i++){
trees1_2[k]=trees1[i];
k++;
}
socket.close();
}
}
(9) client_upload.java(上传按钮客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
public class client_upload implements ActionListener {
String name;
int fileLength;
FileInputStream filestream;
SequenceInputStream siStream;
Socket socket;
BufferedOutputStream outputStream;
ByteArrayInputStream lenStream;
ByteArrayInputStream nameStream;
ByteArrayInputStream idStream;
String str;
JTextField strr;
String ID;
public void setID3(String id){
ID = new String(id);}
public void setStr(JTextField a){
strr = a;
}
client_upload(){
}
public void actionPerformed(ActionEvent eee) {
str = strr.getText();
File file = new File(str);
if(!file.exists()){
JOptionPane.showMessageDialog(null,"文件路径不存在","ERROR",JOptionPane.ERROR_MESSAGE);
return;
}
try{
name = file.getName();
fileLength = (int)file.length();
filestream = new FileInputStream(file);
} catch (IOException e){
System.out.println("建立流错误!");
}
byte[] idName = ID.getBytes();
byte[] idName1 = new byte[256];
for(int i=0; i< idName.length;i++){
idName1[i] = idName[i];
}
idStream = new ByteArrayInputStream(idName1);
byte[] fileName = name.getBytes();
byte[] fileName1 = new byte[256];
for(int i=0; i< fileName.length;i++){
fileName1[i] = fileName[i];
}
nameStream = new ByteArrayInputStream(fileName1);
byte[] fileLen = String.valueOf(fileLength).getBytes();
byte[] fileLen1 = new byte[8];
for(int j=0;j<fileLen.length;j++){
fileLen1[j] = fileLen[j];
}
lenStream = new ByteArrayInputStream(fileLen1);
Vector<InputStream>vec = new Vector<>();
vec.addElement(idStream);
vec.addElement(nameStream);
vec.addElement(lenStream);
vec.addElement(filestream);
Enumeration<InputStream>enumr = vec.elements();
siStream = new SequenceInputStream(enumr);
try {
socket = new Socket("localhost", 4321);
} catch (IOException e) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
try{
outputStream = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[65560];
int leng;
while((leng = siStream.read(buf))!=-1){
outputStream.write(buf,0,leng);
}
System.out.println("上传成功!");
JOptionPane.showMessageDialog(null,"上传成功!");
if(outputStream!=null){
outputStream.close();
}
if(siStream!=null){
siStream.close();
}
if(lenStream!=null){
lenStream.close();
}
if(nameStream!=null){
nameStream.close();
}
if(filestream!=null){
filestream.close();
}}catch (IOException e){
System.out.println("建立流错误!");
}
}
}
(10) client_download.java(下载按钮客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
public class client_download implements ActionListener {
Socket socket;
OutputStream out;
String s;
String ID;
String ID_s;
String store;
JTextField strr;
public void setName(String ss){
s = ss;
}
public void setID7(String s){
ID=s;
}
public void setStr(JTextField a){
strr = a;
}
public void actionPerformed(ActionEvent e) {
store = strr.getText();
try {
socket = new Socket("localhost", 11000);
} catch (IOException ee) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
try{
out = socket.getOutputStream();
ID_s = ID+","+s;
out.write(ID_s.getBytes());
System.out.println("正在传输...");
File receivefile = new File(store+"\\"+s);
if(!receivefile.exists()){
receivefile.createNewFile();
}
FileOutputStream fileout = new FileOutputStream(receivefile);
InputStream inputStream = socket.getInputStream();
byte[] filestream = new byte[65560];
int length1 = 0;
int len = 0;
while((len = inputStream.read(filestream))!=-1){
fileout.write(filestream,0,len);
length1+=len;
}
socket.close();
}catch (IOException ee){
JOptionPane.showMessageDialog(null,"出现错误","ERROR",JOptionPane.ERROR_MESSAGE);
}
System.out.println("下载成功!");
JOptionPane.showMessageDialog(null,"下载成功!");
}
}
(11) client_rename.java(重命名按钮客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class client_rename implements ActionListener {
JTextField name1;
Socket socket;
String rename;
OutputStream out;
String ID;
String s;
String ID_s_re;
public void setStr(JTextField a){
name1 = a;
}
public void setName(String ss){
s = ss;
}
public void setID6(String s){
ID=s;
}
public void actionPerformed(ActionEvent e) {
rename = name1.getText();
try {
socket = new Socket("localhost", 8999);
} catch (IOException ee) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
try{
out = socket.getOutputStream();
ID_s_re = ID+","+s+","+rename;
out.write(ID_s_re.getBytes());
System.out.println("正在修改文件名...");
socket.close();
}catch (IOException ee){
JOptionPane.showMessageDialog(null,"出现错误","ERROR",JOptionPane.ERROR_MESSAGE);
}
System.out.println("修改成功!");
JOptionPane.showMessageDialog(null,"修改成功!");
}
}
(12) client_del.java(删除按钮客户端,涉及Socket的C端)
package Final_Project;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class client_del implements ActionListener {
Socket socket;
String s;
OutputStream out;
String ID;
String ID_s;
public void setName(String ss){
s = ss;
}
public void setID5(String s){
ID=s;
}
public void actionPerformed(ActionEvent e) {
try {
socket = new Socket("localhost", 10800);
} catch (IOException ee) {
JOptionPane.showMessageDialog(null,"找不到服务器","ERROR",JOptionPane.ERROR_MESSAGE);
}
try{
out = socket.getOutputStream();
ID_s = ID+","+s;
out.write(ID_s.getBytes());
System.out.println("正在删除...");
socket.close();
}catch (IOException ee){
JOptionPane.showMessageDialog(null,"出现错误","ERROR",JOptionPane.ERROR_MESSAGE);
}
System.out.println("删除成功!");
JOptionPane.showMessageDialog(null,"删除成功!");
}
}
(1) server_test.java(登录验证服务端,涉及Socket的S端)
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class server_test implements Runnable{
ServerSocket server;
Socket socket;
InputStream in;
OutputStream out;
String idpwd;
int flag = 0;
server_test() {
try {
server = new ServerSocket(10004);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
} catch (IOException e) {
System.out.println("建立连接出错!");
}
}
public void run(){
try{
while(true){
in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
idpwd = new String(buf,0,len);
String[] strmsg = idpwd.split(",");
System.out.println("账号为:"+strmsg[0]);
System.out.println("密码为:"+strmsg[1]);
out = socket.getOutputStream();
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "Aa88888888");//该语句密码需根据实际情况更改
System.out.println("正在验证账号密码...");
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from pan;");
while (rs.next()) {
String id1 = rs.getString("id");
String pw1 = rs.getString("password");
if (strmsg[0].equals(id1) && strmsg[1].equals(pw1))
{
flag = 1;
break;}
}
if(flag == 1){
out.write(1);
System.out.println("Right!");
flag = 0;
}
else{
out.write(0);
System.out.println("Incorrect!");
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
Thread.sleep(200);
socket.close();
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_test();
}
}
(2) server_tree.java(获取管理界面文件信息服务端,涉及Socket的S端)
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class server_tree implements Runnable{
ServerSocket server;
Socket socket;
InputStream in;
OutputStream out;
String ID;
String trees1 = "";
String trees2 = "";
String trees = null;
server_tree(){
try {
server = new ServerSocket(8888);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
} catch (IOException e) {
System.out.println("建立连接出错!");
}
}
public void run(){
try{
while(true){
in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
ID = new String(buf,0,len);
System.out.println("账号为:"+ID);
out = socket.getOutputStream();
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "Aa88888888");//该语句密码需根据实际情况更改
System.out.println("正在拾取个人文件信息...");
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from hub where ID =\'"+ID+"\';");
while(rs.next()){
trees1 = trees1+rs.getString("name")+",";
}
rs = stmt.executeQuery("select * from hub where ID ='903';");
while(rs.next()){
trees2 = trees2+rs.getString("name")+",";
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
trees = trees1+"903,"+trees2;
out.write(trees.getBytes());
Thread.sleep(200);
socket.close();
trees = null;
trees1 = "";
trees2 = "";
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_tree();
}
}
(3) server_upload.java(上传按钮服务端,涉及Socket的S端)
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class server_upload implements Runnable{
ServerSocket server;
Socket socket;
server_upload() {
try {
server = new ServerSocket(4321);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
}catch (IOException e){
System.out.println("建立连接出错!");}
}
public void run(){
try{
while(true){
InputStream inputStream = socket.getInputStream();
byte[] idbyte = new byte[256];
byte[] namebyte = new byte[256];
byte[] length = new byte[8];
inputStream.read(idbyte);
inputStream.read(namebyte);
inputStream.read(length);
String id = new String(idbyte).trim();
System.out.println("id为:"+id);
String name = new String(namebyte).trim();
System.out.println("文件名称为:"+name);
File newFile = new File("d:\\MyHub\\"+id);
if(!newFile.exists()){
boolean isSuccess = newFile.mkdir();
System.out.println("成功创建文件夹了吗? "+isSuccess);
}
File receivefile = new File("d:\\MyHub\\"+id+"\\"+name);
if(!receivefile.exists()){
receivefile.createNewFile();
}
FileOutputStream fileout = new FileOutputStream(receivefile);
System.out.println("文件大小为:"+new String(length).trim());
int fileleng = Integer.valueOf(new String(length).trim());
byte[] filestream = new byte[65560];
int length1 = 0;
int len = 0;
while((len = inputStream.read(filestream))!=-1){
fileout.write(filestream,0,len);
length1+=len;
}
if(fileleng == receivefile.length()){
System.out.println("文件传输成功,丢包率为0");
}
else{
System.out.println("文件传输失败");
}
int flag = 0;
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "Aa88888888");//该语句密码需根据实际情况更改
System.out.println("正在修改数据库数据...");
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from hub;");
while(rs.next()){
String name1 = rs.getString("name");
String id1 = rs.getString("id");
if(name1.equals(name) && id1.equals(id)){
flag=1;
System.out.println("文件名重叠,将覆盖原文件...");
break;
}
}
if(flag == 0){
stmt.executeUpdate("insert into hub values('"+id+"','"+name+"');");
flag=0;
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
Thread.sleep(200);
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_upload();
}
}
(4) server_download.java(下载按钮服务端,涉及Socket的S端)
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
public class server_download implements Runnable{
ServerSocket server;
Socket socket;
InputStream in;
String s;
String ID;
String name;
String str;
FileInputStream filestream;
SequenceInputStream siStream;
BufferedOutputStream outputStream;
server_download(){
try {
server = new ServerSocket(11000);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
} catch (IOException e) {
System.out.println("建立连接出错!");
}
}
public void run(){
try{
while(true) {
in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
s = new String(buf, 0, len);
String[] strmsg = s.split(",");
ID = strmsg[0];
name = strmsg[1];
System.out.println("需要传输的文件属于:" + ID);
System.out.println("其名称为:" + name);
str = "D:\\MyHub\\"+ID+"\\"+name;
File file = new File(str);
if(!file.exists()){
System.out.println("文件不存在!");
return;
}
try{
filestream = new FileInputStream(file);
} catch (IOException e){
System.out.println("建立流错误!");
}
Vector<InputStream> vec = new Vector<>();
vec.addElement(filestream);
Enumeration<InputStream> enumr = vec.elements();
siStream = new SequenceInputStream(enumr);
outputStream = new BufferedOutputStream(socket.getOutputStream());
byte[] buff = new byte[65560];
int leng;
while((leng = siStream.read(buff))!=-1){
outputStream.write(buff,0,leng);
}
System.out.println("成功读入!");
if(outputStream!=null){
outputStream.close();
}
if(siStream!=null){
siStream.close();
}
if(filestream!=null){
filestream.close();
}
Thread.sleep(200);
socket.close();
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_download();
}
}
(5) server_rename.java(重命名按钮服务端,涉及Socket的S端)
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class server_rename implements Runnable {
ServerSocket server;
Socket socket;
InputStream in;
String s;
String ID;
String name;
String rename;
server_rename() {
try {
server = new ServerSocket(8999);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
} catch (IOException e) {
System.out.println("建立连接出错!");
}
}
public void run(){
try{
while(true){
in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
s = new String(buf,0,len);
String[] strmsg = s.split(",");
ID = strmsg[0];
name = strmsg[1];
rename = strmsg[2];
System.out.println("需要修改的文件属于:"+ID);
System.out.println("其名称为:"+name);
System.out.println("它将被重命名为:"+rename);
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "Aa88888888");//该语句密码需根据实际情况更改
System.out.println("正在修改文件...");
stmt = conn.createStatement();
stmt.executeUpdate("update hub set name = '"+rename+"'where id = '"+ID+"' and name = '"+name+"';");
System.out.println("修改成功!");
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
String road = "D:\\MyHub\\"+ID+"\\"+name;
File file = new File(road);
file.renameTo(new File("D:\\MyHub\\"+ID+"\\"+rename));
Thread.sleep(200);
socket.close();
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_rename();
}
}
(6) server_delete.java(删除按钮服务端,涉及Socket的S端)
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class server_delete implements Runnable{
ServerSocket server;
Socket socket;
InputStream in;
String s;
String ID;
String name;
server_delete() {
try {
server = new ServerSocket(10800);
while (true) {
socket = server.accept();
Thread t = new Thread(this);
t.start();
}
} catch (IOException e) {
System.out.println("建立连接出错!");
}
}
public void run(){
try{
while(true){
in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
s = new String(buf,0,len);
String[] strmsg = s.split(",");
ID = strmsg[0];
name = strmsg[1];
System.out.println("需要删除的文件属于:"+ID);
System.out.println("其名称为:"+name);
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "Aa88888888");//该语句密码需根据实际情况更改
System.out.println("正在删除文件...");
stmt = conn.createStatement();
stmt.executeUpdate("delete from hub where id = '"+ID+"'and name = '"+name+"';");
System.out.println("删除成功!");
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
Thread.sleep(200);
socket.close();
}
}catch (IOException e){
System.out.println("线路上读写信息出错");}
catch (Exception ee){
System.out.println("线程出错");}
}
public static void main(String[] args) {
new server_delete();
}
}
注:这不是严格意义上的论文,更多的是根据老师的问题来逐一回答
问题一:项目描述:题目名称及背景概况。
题目名称:903小型宿舍文件仓储系统
背景概况:当今,各种网盘得到日益广泛的应用。尤其对于有着大量文件管理需求的大学生,网盘系统提供了便捷的文件存储管理功能,节省了大量学习时间以及本机的硬盘空间。但是网盘功能过于繁杂,开发难度大。而宿舍作为大学生交流的主要单位,小型易用的宿舍文件仓储系统即可满足舍友之间的资源交流的需求。
问题二:项目分析:项目的目的、用途或需要解决的问题以及需求。
项目目的:本系统开发的总体任务是实现宿舍文件的管理与共享。系统要完成宿舍文件的管理,应包括:对文件共享性的分类;文件上传;文件下载;文件删除;文件重命名等功能。
项目用途:本系统通过局域网使得舍友之间实现文件共享,从而实现重要文件的存储管理,并且实现硬盘空间的合理分配。
项目需要解决的问题:宿舍部分成员出现硬盘容量不足的问题,宿舍部分成员文件存储混乱易丢失的问题,宿舍成员间共享文件困难的问题。
项目需求:
硬件环境:
a) 处理器:Intel i7 9750H
b) 内存:24GB
c) 硬盘空间:1T
软件环境:
a) 操作系统:Windows 10
b) 集成开发环境:IntelliJ IDEA
c) 数据库:PostgreSQL
问题三:设计:功能设计、界面设计、数据结构和数据库设计、对象和类设计、文件系统目录结构设计。
该界面设计非常简洁,登录界面上方标签展示了该系统的名称以及“乐在分享”的理念,主体部分只需输入账号密码,点击登录按钮即可。其中账号密码需要提前在服务端主机的PostgreSQL数据库中使用sql语句录入。
该界面设计非常简洁,左侧为文件目录,右侧为功能按钮。其中文件夹目录分为共享文件和个人文件,其中共享文件在不同用户间均可见,而个人文件仅当前用户可见。在选择文件夹后,“上传文件”按钮功能将可见,而在选择具体文件后,“下载文件”、“删除文件”和“文件重命名”按钮功能将可见。
在点击文件管理界面“上传文件”后,将会出现上传文件界面。该界面设计非常简洁,输入本地文件路径后,点击“开始上传”即可完成本地文件传输至服务器仓库,并修改服务器数据库的文件信息。
在点击文件管理界面“下载文件”后,将会出现下载文件界面。该界面设计非常简洁,输入需要将文件存储到的本地地址后,点击“开始下载”即可完成服务器仓库文件传输并保存至本地目标路径。
在点击文件管理界面 “删除文件”后,将会出现文件删除界面。这是为了防止误操作。点击确认按钮后,即可删除文件。需注意,该删除操作只是删除服务器数据库中的该文件信息,该文件将不再可以通过该系统管理,但其仍存储在服务器主机仓库中。
在点击文件管理界面“文件重命名”后,将会出现文件重命名界面。该界面设计非常简洁,输入所需重命名文件的名称后,点击“确认”即可完成服务器数据库与仓库文件信息的修改。
该系统包括登录功能和文件管理功能,所以数据库应包括用户信息表pan以及文件信息表hub。其中pan用于存储用户账号与密码信息,hub用于存储文件所属用户与文件名称信息,默认903为共享文件所属用户名。以上信息均使用PostgreSQL实现管理,用户的账号密码信息需在使用前提前在服务器数据库录入。
该系统包含客户端和服务端两部分。其中客户端是名为“2020_Final_Project”的文件夹,主要包括12个类;服务端共有6个程序,分别处理登录请求、文件管理界面请求、文件上传请求、文件下载请求、文件删除请求、文件重命名请求。以下通过UML图展示这些对象和类。
文件系统目录结构是以Hashtable构建JTree,以下为定义JTree与Hashtable:
JTree tree;
Hashtable hashtable1;
Hashtable hashtable2;
具体而言,Hashtable1将表示一级目录“903网盘”,Hashtable2将表示二级目录“个人文件”和“共享文件”。就意义而言,共享文件将由所有用户共同管理,而个人文件只属于当前用户。其中,个人文件中所有文件名称信息将被存储在数组s1中,而共享文件中所有文件名称信息将被存储在数组s2中。具体代码如下:
hashtable1 = new Hashtable();
hashtable2 = new Hashtable();
hashtable1.put("903网盘",hashtable2);
hashtable2.put("共享文件",s2);
hashtable2.put("个人文件",s1);
tree = new JTree(hashtable1);
问题四:主要功能或算法描述及流程。
Ø 客户端:
首先显示登录界面,用户需要输入账号与密码。其中账号输入JTextField,密码输入JPasswordField。在点击“登录”后,将会执行Client_test过程,并将JTextField和JPassword的信息传递给Client_test。关闭登录界面即可使系统停止运行。
该过程会将JTextField以及JPasswordField中的内容转化成字符串后用“,”连接,并通过socket通信将该字符串信息发送至服务器进行Server_test过程验证。若验证通过,则服务器返回1,反之返回0。若返回1,则将进行Management过程;若返回0,则显示登录失败,并要求用户重新输入。
该过程将当前用户的账号(即ID信息)通过socket发送至服务器进行Server_tree过程,服务器根据ID号寻找到其下个人文件信息,同时将共享文件信息与个人文件信息以标记好的字符串形式返回给客户端,而该字符串将被重新解析成两个字符串数组s1和s2,分别代表个人文件信息与共享文件信息,并传递给Management过程。
该过程将根据字符串数组s1和s2在界面左侧显示文件目录,而在界面右侧显示“上传文件”、“下载文件”、“删除文件”和“文件重命名”四个按钮,这四个按钮分别对应Jbt_up过程、Jbt_down过程、Jbt_del过程和Jbt_re过程。其中,当文件目录中文件夹(即“个人文件”或“共享文件”)被选中时,仅“上传文件”按钮可进行操作;而当文件夹下文件被选中时,仅“上传文件”按钮不可进行操作。在进行四个按钮的相应操作后,文件目录无法实现自动刷新,需要重新关闭该界面(系统仍会运行),重新进行Login过程登录。(由于登录后登录界面的账号密码仍保留,故只需点击登录按钮即可再次登录)。在进行四个按钮的操作时,将会以字符串形式分别将当前用户ID以及当前文件夹(或文件)信息传递至相应过程。
将会显示上传文件界面。用户需要输入所需上传文件在本地的路径,并点击“开始上传”,之后将会调用Client_upload过程。该过程还将会以字符串的形式将当前用户ID以及文件本地路径传递给Client_upload过程。
先通过文件路径寻找本地文件,若文件路径不存在将会报错。之后将会获取文件名称与大小,并将用户ID、文件名称和文件大小存放于Vector数组中。此时该过程将会利用socket尝试与服务器连接,若连接失败会报错。连接成功后,该过程将分别把文件内容以及Vector数组发送给服务器进行Server_upload过程,并向用户表示上传成功。
将会显示下载文件界面。用户需要输入所需将目标文件下载至本地的路径,并点击“开始下载”,之后将会调用Client_download过程。该过程还将会以字符串的形式将当前用户ID、目标文件名称和文件本地路径传递给Client_download过程。
首先将尝试通过socket与服务器连接,若连接失败会报错。连接成功后,该过程将会把用户ID与目标文件名称以“,”连接成字符串后传递给服务器进行Server_download过程。之后该过程将会接收由服务器传输返回的文件内容,并将其存储在用户指定的路径,同时向用户表示下载成功。
将会显示再次确认界面,以防止用户误操作。在用户点击“确认”按钮后,将会调用Client_delete过程。该过程还将会以字符串的形式将当前用户ID以及目标文件名称传递给Client_delete过程。
首先将尝试通过socket与服务器连接,若连接失败会报错。连接成功后,该过程将会把用户ID与目标文件名称以“,”连接成字符串后传递给服务器进行Server_delete过程,并向用户表示删除成功。
将会显示文件重命名界面。用户需要输入所需将目标文件下载至本地的路径,并点击“确认”,之后将会调用Client_rename过程。该过程还将会以字符串的形式将当前用户ID、目标文件名称和重命名名称传递给Client_rename过程。
首先将尝试通过socket与服务器连接,若连接失败会报错。连接成功后,该过程将会把用户ID、目标文件名称和重命名名称以“,”连接成字符串后传递给服务器进行Server_rename过程,并向用户表示重命名成功。
Ø 服务器:
在与Client_test过程取得联系后,该过程将会把收到的字符串重新解析成账号与密码信息并存储与字符串数组中。之后该过程将会与服务端主机数据库PostgreSQL中的用户信息表pan获得联系(其中密码因主机不同而异,需要根据本机修改程序),并通过数据库查询语句对比是否存在账号、密码均吻合的数据。若存在,则向客户端发送整数1,即表示验证通过;若不存在,则向客户端发送整数0,即表示验证失败。需注意该系统数据库中用户信息表只能直接在服务器的PostgreSQL中修改,无法在客户端进行注册等操作。
在与Client_tree过程取得联系后,该过程将会根据收到的ID信息查找服务端主机数据库PostgreSQL中的文件信息表hub(同上,若希望与PostgreSQL数据库连接,其密码因主机不同而异,需要根据本机修改程序),并将对应的个人文件信息与共享文件以“,”连接成字符串,并在二者间以“903”为标志分隔。之后,该过程会将该字符串发送给客户端。
在与Client_upload过程取得联系后,该过程将会根据收到用户ID、文件名称和文件内容在服务器主机创建对应路径并存储文件,并将接收到的文件大小与客户端发送的文件大小信息比对,若相同,则显示丢包率为0。本系统程序使用“D:\MyHub”为仓库的路径,并在其中创建以用户ID命名的文件夹,文件夹内存储文件,同时默认“903”为共享文件存储地址。之后,该过程将会与PostgreSQL连接(同上,其密码因主机不同而异,需要根据本机修改程序),并根据用户ID与文件名称修改文件信息表hub中的数据(即增加新的文件信息数据)。若同名文件已存在,该过程将覆盖原有文件。
在与Client_download过程取得联系后,该过程将会根据收到用户ID及文件名称在服务器主机找到仓库对应文件,并将文件内容传递给客户端。
在与Client_delete过程取得联系后,该过程将会根据收到用户ID和文件名称删除文件信息数据库hub中的对应文件信息数据。(同上,若希望与PostgreSQL数据库连接,其密码因主机不同而异,需要根据本机修改程序)。需注意服务器主机本地仓库中该文件将不会被删除,若需彻底删除,可在主机上直接操作。该设定是为了在用户误删后仍可通过服务器管理员找回文件。
在与Client_rename过程取得联系后,该过程将会根据收到用户ID、文件名称和重命名名称修改文件信息数据库hub中的对应文件信息数据。(同上,若希望与PostgreSQL数据库连接,其密码因主机不同而异,需要根据本机修改程序)。之后,该过程会将服务器主机本地仓库中的该文件重命名。
问题五:文献资料
[1] Bruce Eckel. (2007)
Thinking in Java. Beijing, China Machine Press.
[2] Y.Daniel Liang. (2006)
Introduction to Java Programming. Beijing, China Machine Press.
[3] 张思民. (2015) Java语言程序设计. 北京, 清华大学出版社.
[4] 黄明, 梁旭 & 曹利超. (2005) Java信息系统设计与开发实例. 北京, 机械工业出版社.
[5] Abraham Silberschatz,
Henry F. Korth & S. Sudarshan. (2012) Database System Concepts. Beijing,
China Machine Press.
[6] Runoob. (2020) Java菜鸟教程. [Online] Available from:
https://www.runoob.com/java/java-tutorial.html
[Accessed 30th July 2020]
[7] Oracle. (2020) Java™
Platform Standard Ed. 8. [Online] Available from: https://docs.oracle.com/javase/8/docs/api/
[Accessed 30th July 2020]
[8] 郑人杰. (1986) 软件详细设计中的算法描述工具. 微型机与应用. [Online] (02):13-17.
Available from: https://www.ixueshu.com/document/c2f1afb362c2fded8b6d715b637b3829318947a18e7f9386.html
[Accessed 15th August 2020]
截取信中有关本文的部分:
详见我的另一篇博文:
https://blog.csdn.net/qq_45681057/article/details/108045434
还是得根据对称的思想来学习吧,毕竟大量知识是可以重复利用的。
这个项目的耗时不是很长,大概从只有基本的java知识开始做,短短续续的用5天即可完成,此后疲于精细化修改,故提前上交了。
可以说,笔者对自己的项目有很多不满意地方:
这门课其实基本上就是自学,老师确实上了三节网课,但是所学知识太过基础,无法应用于解决实际项目的主要矛盾。但是这些基础对于曾经零基础的同学来说是好的,至少给予了他们基础的学习手段,以及规划了一部分学习时间。
夏季学期结束后,就是暑假结束了。暑假结束后是军训,军训在昨天结束了。今天有空闲与心情文以记夏季学期之实践大题,且回味往事,而如今秋意渐浓,暂时写到这吧。