diff --git a/src/client/Client.java b/src/client/Client.java index 54dbebf..fa2cc00 100644 --- a/src/client/Client.java +++ b/src/client/Client.java @@ -30,46 +30,44 @@ import server.vo.User; public class Client { - // 多个函数共享的数据可以定义为全局的 - public static Scanner scan = new Scanner(System.in); // 控制台输入 - public static Socket socket; // 建立连接后的套接字对象 - public static BufferedReader buf; // 字符输入流 - public static PrintWriter write; // 字符输出流 - public static User currentUser; // 当前登录用户 + public static Scanner scan = new Scanner(System.in); + public static Socket socket; + public static BufferedReader buf; + public static PrintWriter write; + public static User currentUser; public static Connection con = null; public static PreparedStatement ps = null; public static Statement statement = null; public static ResultSet rs = null; - // 主方法 public static void main(String[] args) throws Exception, IOException { - String ip = "127.0.0.1"; // 服务器IP - int port = 9999; // 服务器程序的端口 - // 1.建立与服务器的连接 + String ip = "127.0.0.1"; + int port = 9999; + socket = new Socket(ip, port); - // 获取输入流 + InputStream is = socket.getInputStream(); buf = new BufferedReader(new InputStreamReader(is, "utf-8")); - // 获取输出流 + OutputStream os = socket.getOutputStream(); write = new PrintWriter(new OutputStreamWriter(os, "utf-8")); - // 2.用户登录 - if (!login()) { // 登录失败,退出程序 + + if (!login()) { System.out.println("登录失败,欢迎下次访问"); System.exit(0); } - // 登录成功,显示程序主界面 + int choose = menu(); - while (choose != 8) { // 不是退出 + while (choose != 8) { switch (choose) { case 1: display(); break; - case 2:// 当当网站爬取 + case 2: Driver.crawl(); break; - case 3:// 查询 + case 3: query(); break; case 4: @@ -87,18 +85,17 @@ public class Client { default: break; } - choose = menu(); // 执行完毕,重新显示主菜单,并选择 + choose = menu(); } - // 输入选择=8,退出 + close(); System.out.println("您已退出程序,欢迎下次使用!"); } - // 选择退出时,先向服务器发送“退出请求:code=8”,然后关闭连接 public static void close() throws Exception { Map map = new HashMap<>(); map.put("code", 8); - String sendData = new Gson().toJson(map); // 将java的map对象直接转换成json字符串 + String sendData = new Gson().toJson(map); System.out.println("发送给服务器:" + sendData); write.println(sendData); write.flush(); @@ -113,24 +110,22 @@ public class Client { } } - // 绘制流程图,按流程图书写 public static boolean login() throws Exception { for (int i = 1; i <= 3; i++) { - // 1.输入用户名,密码:所有输入均应该先给输入提示 + System.out.println("请输入用户名:"); String userName = scan.nextLine(); System.out.println("请输入密码:"); String passsord = scan.nextLine(); - // 可以使用GSON包非常方便的将java类型的数据转成json字符串,或者从json字符串中获取相关的数据,见教案p129 - // 封装发送的数据:如登录请求的数据格式可以为"{code:0,data:{userName:***,password:***}}" + Map map = new HashMap<>(); map.put("code", 0); User user = new User(); user.setUserName(userName); user.setPassword(passsord); Gson gson = new Gson(); - map.put("data", gson.toJson(user)); // toJson方法可以将java的vo对象直接转换成json字符串 - String sendData = gson.toJson(map); // 将java的map对象直接转换成json字符串 + map.put("data", gson.toJson(user)); + String sendData = gson.toJson(map); System.out.println("发送给服务器:" + sendData); /** * 2.发送数据并接收服务器返回的数据(返回数据也有格式,如可以是以下格式: @@ -140,15 +135,15 @@ public class Client { */ String responseData = send(sendData); System.out.println("接收到服务器端的响应:" + responseData); - // 4.解析返回的字符串 - JsonElement element = JsonParser.parseString(responseData); // 使用parseString方法将json字符串转换为JsonElement对象 - JsonObject obj = element.getAsJsonObject(); // 将JsonElement对象转换为JsonObject对象 - int returnCode = obj.get("code").getAsInt(); // 获取code属性 - String returnData = obj.get("data").getAsString(); // 获取data属性 - if (returnCode == 0) { // 登录失败 + + JsonElement element = JsonParser.parseString(responseData); + JsonObject obj = element.getAsJsonObject(); + int returnCode = obj.get("code").getAsInt(); + String returnData = obj.get("data").getAsString(); + if (returnCode == 0) { System.out.println("登录失败:" + returnData); - } else { // 登录成功,returnData中存放的是当前用户的json字符串 - currentUser = gson.fromJson(returnData, User.class); // 使用fromJson方法可以将json字符串直接转换为指定类型的对象 + } else { + currentUser = gson.fromJson(returnData, User.class); return true; } @@ -158,17 +153,16 @@ public class Client { } - // 显示操作界面,返回用户的选择1,2,..... public static int menu() { System.out.println("======图书数据助理系统======="); System.out.println("当前用户:" + currentUser.getName()); System.out.println("1.图书信息显示"); - System.out.println("2.当当网站爬取"); // 需要增加二级菜单:【键盘录入,网页爬取,txt文件导入,xls文件导入】 - System.out.println("3.查询"); // 按key修改其他字段 - System.out.println("4.删除"); // 按key删除记录 - System.out.println("5.修改"); // 需要增加二级菜单,【自动设计查询条件】 - System.out.println("6.导出到csv文件"); // 需要增加二级菜单,【自行设计统计条件】 - System.out.println("7.导出到xls文件"); // 需要增加二级菜单:【导出至txt,导出至xls】 + System.out.println("2.当当网站爬取"); + System.out.println("3.查询"); + System.out.println("4.删除"); + System.out.println("5.修改"); + System.out.println("6.导出到csv文件"); + System.out.println("7.导出到xls文件"); System.out.println("8.退出"); System.out.println("请输入选项(1-8):"); @@ -177,12 +171,11 @@ public class Client { return choose; } - // 将指定的字符串发送给服务器,并接收服务器返回的数据 public static String send(String data) throws Exception { - // 发送数据 + write.println(data); write.flush(); - // 接收数据 + String response = buf.readLine(); return response; } @@ -194,7 +187,7 @@ public class Client { statement = con.createStatement(); rs = statement.executeQuery(sql); while (rs.next()) { - // System.out.println(rs.getString(1)); + Book book = new Book(); book.setTitle(rs.getString(1)); @@ -204,7 +197,7 @@ public class Client { book.setNewprice(rs.getDouble(5)); book.setHref(rs.getString(6)); - // System.out.println(book.getHref()); + System.out.println(book.toString()); } } catch (Exception e) { @@ -239,22 +232,22 @@ public class Client { int n = 0; n = scan.nextInt(); switch (n) { - case 1:// 名称查询 + case 1: sql = "select * from book where title like ?"; System.out.println("请输入名称:"); outputQuery(sql); break; - case 2:// 作者查询 + case 2: sql = "select * from book where author like ?"; System.out.println("请输入作者:"); outputQuery(sql); break; - case 3:// 出版社查询 + case 3: sql = "select * from book where publisher like ?"; System.out.println("请输入出版社:"); outputQuery(sql); break; - case 4:// 价格查询 + case 4: sql = "select * from book where newprice like ?"; System.out.println("请输入价格:"); outputQuery(sql); @@ -268,9 +261,7 @@ public class Client { con = DBConnection.getConnection(); String title, author, pubilsher, oldprice, newprice, url; String inquire = scan.next(); - // Connection con = DBConnection.getConnection(); - // PreparedStatement ps =null; - // ResultSet rs=null; + try { ps = con.prepareStatement(sql); ps.setString(1, '%' + inquire + '%'); @@ -317,8 +308,8 @@ public class Client { String sql = null; System.out.println("======修改图书======="); System.out.println("1.修改作者姓名"); - System.out.println("2.修改出版社"); // 需要增加二级菜单:【键盘录入,网页爬取,txt文件导入,xls文件导入】 - System.out.println("3.修改价格"); // 按key修改其他字段 + System.out.println("2.修改出版社"); + System.out.println("3.修改价格"); System.out.println("4.退出"); System.out.println("请输入需要修改的图书的名称"); String title = scan.next(); diff --git a/src/server/Server.java b/src/server/Server.java index bc4c2a0..debf685 100644 --- a/src/server/Server.java +++ b/src/server/Server.java @@ -8,15 +8,15 @@ import server.thread.HandleThread; public class Server { public static void main(String[] args) throws Exception { - // 创建服务器 + int port = 9999; ServerSocket server = new ServerSocket(port); System.out.println("服务器正在 9999 端口侦听客户端请求"); - // 循环等待客户端请求 + while (true) { Socket socket = server.accept(); System.out.println("客户端" + socket.getInetAddress().getHostAddress() + "成功连接"); - // 新建一个线程来处理该处理该请求(实现并发) + new HandleThread(socket).start(); } diff --git a/src/server/dao/UserDAO.java b/src/server/dao/UserDAO.java index 5c62794..6a032ed 100644 --- a/src/server/dao/UserDAO.java +++ b/src/server/dao/UserDAO.java @@ -9,20 +9,20 @@ import server.tools.DBConnection; import server.vo.User; public class UserDAO { - // 按关键字进行查询,返回查询结果(vo对象,因为查询结果最多一条),没有查询到,则返回null + public static User get(String userName) throws Exception { User user = null; - // 获取连接 + Connection con = DBConnection.getConnection(); - // 操作对应sql语句,支持参数 + String sql = "select * from user where userName=?"; - // 创建语句对象 + PreparedStatement pst = con.prepareStatement(sql); - // 对sql语句的?参数进行赋值 + pst.setString(1, userName); - // 执行select查询语句,如果sql语句是insert,update或delete,则需调用executeUpdate进行执行 + ResultSet rs = pst.executeQuery(); - // 将记录集转换为vo对象 + while (rs.next()) { user = new User(); user.setUserName(rs.getString("userName")); @@ -30,32 +30,31 @@ public class UserDAO { user.setName(rs.getString("name")); user.setRole(rs.getString("role")); } - // 关闭连接对象 + DBConnection.close(con, pst); return user; } - // 按任意条件组合查询,将查询结果存放在集合中【因为可能有多条】 public static ArrayList query(User userCondition) throws Exception { ArrayList list = new ArrayList(); - // 获取连接 + Connection con = DBConnection.getConnection(); - // 操作对应sql语句 + String sql = "*******"; - // 创建语句对象 + PreparedStatement pst = con.prepareStatement(sql); - // 执行select查询语句,如果sql语句是insert,update或delete,则需调用executeUpdate进行执行 + ResultSet rs = pst.executeQuery(); - // 将记录集转换为vo对象 + while (rs.next()) { User user = new User(); user.setUserName(rs.getString("userName")); user.setPassword(rs.getString("password")); user.setName(rs.getString("name")); user.setRole(rs.getString("role")); - list.add(user); // 将对象增加到集合中 + list.add(user); } - // 关闭连接对象 + DBConnection.close(con, pst); return list; diff --git a/src/server/thread/HandleThread.java b/src/server/thread/HandleThread.java index 17b58bc..d4020ce 100644 --- a/src/server/thread/HandleThread.java +++ b/src/server/thread/HandleThread.java @@ -20,18 +20,17 @@ import server.vo.User; public class HandleThread extends Thread { private Socket socket; - private BufferedReader buf; // 字符输入流 - private PrintWriter write; // 字符输出流 + private BufferedReader buf; + private PrintWriter write; - // 构造方法 public HandleThread(Socket socket) { super(); this.socket = socket; try { - // 获取输入流 + InputStream is = socket.getInputStream(); buf = new BufferedReader(new InputStreamReader(is, "utf-8")); - // 获取输出流 + OutputStream os = socket.getOutputStream(); write = new PrintWriter(new OutputStreamWriter(os, "utf-8")); } catch (Exception e) { @@ -40,27 +39,26 @@ public class HandleThread extends Thread { } - // 具体的请求处理:线程执行start方法时自动调用 @Override public void run() { - while (true) { // 循环接收客户端发送过来的数据 + while (true) { try { - // 接收客户端发送的json字符串 + String receiveStr = buf.readLine(); System.out.println("接收到客户端的请求数据:" + receiveStr); - // 按协议解析字符串,如:code = 0,表示的是登录请求 - JsonElement element = JsonParser.parseString(receiveStr); // 使用parseString方法将json字符串转换为JsonElement对象 - JsonObject obj = element.getAsJsonObject(); // 将JsonElement对象转换为JsonObject对象 - int code = obj.get("code").getAsInt(); // 获取code属性 - if (code == 8) { // 客户端退出 + + JsonElement element = JsonParser.parseString(receiveStr); + JsonObject obj = element.getAsJsonObject(); + int code = obj.get("code").getAsInt(); + if (code == 8) { close(); break; } - String data = obj.get("data").getAsString(); // 获取data属性 + String data = obj.get("data").getAsString(); String response = ""; switch (code) { - case 0: // 登录请求 - response = loginHandle(data); // 登录请求处理,data中存放的是输入的用户名和密码 + case 0: + response = loginHandle(data); break; case 1: @@ -71,7 +69,7 @@ public class HandleThread extends Thread { System.out.println("命令无效!"); break; } - // 向客户端发送响应数据 + write.println(response); write.flush(); @@ -85,7 +83,6 @@ public class HandleThread extends Thread { } - // 客户端选择退出时,关闭连接 public void close() throws Exception { if (write != null) { write.close(); @@ -99,9 +96,9 @@ public class HandleThread extends Thread { } public String loginHandle(String str) throws Exception { - // 解析json字符串,str中的存放的是输入的用户名,密码信息的json格式字符串,使用Gson包将其直接转换为User对象 + User loginUser = new Gson().fromJson(str, User.class); - // 调用DAO,按用户名查询数据库,返回查询结果 + User user = UserDAO.get(loginUser.getUserName()); /** * 根据dao执行结果,给出相应的响应,需要设计响应字符串的协议格式 如可以这样设计:*{code:0 @@ -110,22 +107,22 @@ public class HandleThread extends Thread { * 表示登录成功,data中放当前用户相关的信息(用户名,姓名,角色等) */ String responseData = ""; - if (user == null) { // 登录失败,原因:表示的用户不存在 + if (user == null) { Map map = new HashMap<>(); map.put("code", 0); map.put("data", "用户名不存在"); - responseData = new Gson().toJson(map); // 将java的map对象直接转换成json字符串 - } else { // 有该用户,进一步密码是否正确 - if (loginUser.getPassword().equals(user.getPassword())) { // 用户名密码正确 + responseData = new Gson().toJson(map); + } else { + if (loginUser.getPassword().equals(user.getPassword())) { Map map = new HashMap<>(); map.put("code", 1); - map.put("data", new Gson().toJson(user)); // 使用toJson方法可以将java的vo对象直接转换成json字符串 - responseData = new Gson().toJson(map); // 将java的map对象直接转换成json字符串 - } else { // 密码不正确 + map.put("data", new Gson().toJson(user)); + responseData = new Gson().toJson(map); + } else { Map map = new HashMap<>(); map.put("code", 0); map.put("data", "密码错误"); - responseData = new Gson().toJson(map); // 将java的map对象直接转换成json字符串 + responseData = new Gson().toJson(map); } } return responseData; diff --git a/src/server/tools/DBConnection.java b/src/server/tools/DBConnection.java index f6dc894..5989efb 100644 --- a/src/server/tools/DBConnection.java +++ b/src/server/tools/DBConnection.java @@ -11,7 +11,6 @@ public class DBConnection { private final static String user = "root"; private final static String password = "516849"; - // 加载驱动 static { try { Class.forName(driverName); diff --git a/src/server/tools/Encoding.java b/src/server/tools/Encoding.java index 72cf9cd..9090005 100644 --- a/src/server/tools/Encoding.java +++ b/src/server/tools/Encoding.java @@ -9,7 +9,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Base64; public class Encoding { - // 对指定的字符串进行md5编码 + public static String md5(String password) { try { MessageDigest md = MessageDigest.getInstance("MD5"); @@ -25,7 +25,6 @@ public class Encoding { } } - // 将指定的文件进行base64编码,返回编码字符串 public static String base64FromFile(String filePath) { try { byte[] fileBytes = Files.readAllBytes(Path.of(filePath)); @@ -36,7 +35,6 @@ public class Encoding { } } - // 将base64编码字符串还原为文件,文件路径及文件名为filePath public static void base64ToFile(String base64Str, String filePath) { try { byte[] fileBytes = Base64.getDecoder().decode(base64Str); diff --git a/src/server/tools/ExportToCSV.java b/src/server/tools/ExportToCSV.java index 8d9eca2..942c89e 100644 --- a/src/server/tools/ExportToCSV.java +++ b/src/server/tools/ExportToCSV.java @@ -16,7 +16,7 @@ public class ExportToCSV { ResultSet resultSet = statement.executeQuery("SELECT * FROM book"); FileWriter fileWriter = new FileWriter(outputFile)) { - // Write column names to the CSV file + for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { fileWriter.append(resultSet.getMetaData().getColumnName(i)); if (i < resultSet.getMetaData().getColumnCount()) { @@ -25,7 +25,7 @@ public class ExportToCSV { } fileWriter.append("\n"); - // Write data rows to the CSV file + while (resultSet.next()) { for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { fileWriter.append(resultSet.getString(i)); diff --git a/src/server/tools/crawling/Book.java b/src/server/tools/crawling/Book.java index eda1c3d..8c6fc54 100644 --- a/src/server/tools/crawling/Book.java +++ b/src/server/tools/crawling/Book.java @@ -3,11 +3,11 @@ package server.tools.crawling; public class Book { private String title; - private String author; // 作者 - private String publisher; // 出版社 - private double oldprice; // 出版时间 - private double newprice; // 价格 - private String href; // 图书详情url + private String author; + private String publisher; + private double oldprice; + private double newprice; + private String href; public Book() { } @@ -133,6 +133,5 @@ public class Book { return "Book{title = " + title + ", author = " + author + ", publisher = " + publisher + ", oldprice = " + oldprice + ", newprice = " + newprice + ", href = " + href + "}"; } - // private String imageHref; //封面图片href地址 } diff --git a/src/server/tools/crawling/CrawlerTools.java b/src/server/tools/crawling/CrawlerTools.java index d7137d3..bc7005a 100644 --- a/src/server/tools/crawling/CrawlerTools.java +++ b/src/server/tools/crawling/CrawlerTools.java @@ -12,18 +12,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class CrawlerTools { - // 读取指定url的网页html字符串,需要指定网页的字符编码 + public static String get(String urlStr, String charset) { StringBuffer buf = new StringBuffer(); HttpURLConnection con = null; InputStream in = null; BufferedReader read = null; try { - // // 待爬取的url + URL url = new URL(urlStr); con = (HttpURLConnection) url.openConnection(); - // 模拟浏览器发出请求,防止反爬 con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53"); int code = con.getResponseCode(); @@ -65,7 +64,6 @@ public class CrawlerTools { return buf.toString(); } - // 将url字符串里面的中文进行编码 public static String encodingUrl(String url) { String regex = "[\u4e00-\u9fa5]+"; Pattern pat = Pattern.compile(regex); diff --git a/src/server/tools/crawling/NewsThread.java b/src/server/tools/crawling/NewsThread.java index f33351f..d4722ec 100644 --- a/src/server/tools/crawling/NewsThread.java +++ b/src/server/tools/crawling/NewsThread.java @@ -21,10 +21,9 @@ public class NewsThread implements Runnable { @Override public void run() { - // 对爬取结果解析 String content = CrawlerTools.get(urlPath, "GB2312"); Document doc = Jsoup.parse(content); - Elements elements = doc.select(".bang_wrapper .bang_list_box ul li"); // 所有新闻 + Elements elements = doc.select(".bang_wrapper .bang_list_box ul li"); Connection con = DBConnection.getConnection(); PreparedStatement ps = null; @@ -34,7 +33,7 @@ public class NewsThread implements Runnable { index++; if (index >= 20) break; - // 每本图书的名称,作者,出版社,原价格、折后价格、详情url地址等信息 + String title = bookelement.select(".name a").text(); Elements publisherInfoElements = bookelement.select(".publisher_info"); String author = null; @@ -52,7 +51,7 @@ public class NewsThread implements Runnable { String href = bookelement.select(".name a").attr("href"); double oldprice = Double.parseDouble(oprice.substring(1)); double newprice = Double.parseDouble(nprice.substring(1)); - sql = "insert into book values(?,?,?,?,?,?)";// 书名,作者名,出版社,原价格,折后价格,详情url地址 + sql = "insert into book values(?,?,?,?,?,?)"; try { ps = con.prepareStatement(sql); ps.setString(1, title);