登录,注册
用户信息保存到哪里?
-
集合中, 临时存储, 存储在内存中, 当程序退出运行, 占用内存释放, 数据就没有了
-
使用IO流, 把用户信息保存到本地文件, 推荐xml(数据一定的格式) 适合一些微小型项目
-
使用数据库: 比如mysql, Oracle,… 适合中大型项目
我们这个项目: 使用xml存储
xml类似于html, 使用标签包裹数据
html中的标签固定的, w3c标准组织定义的, 作为页面展示
xml中的标签自定义, 作用: 1) 配置文件, 2) 轻量级的存储
xml格式:
<!--文档声明: 固定的-->
<?xml version="1.0" encoding="utf-8"?>
<根标签>
<子标签 属性名1=值1 属性名2=值2>
<!--其他标签-->
</子标签>
<子标签 属性名1=值1 属性名2=值2>
<!--其他标签-->
</子标签>
</根标签>
使用xml描述一组学生(学号,姓名, 性别,年龄):
students.xml
<?xml version="1.0" encoding="utf-8"?>
<stus>
<student id="1">
<stuNo>1001</stuNo>
<name>张三</name>
<sex>男</sex>
<age>21</age>
</student>
<student>
<stuNo>1002</stuNo>
<name>李四</name>
<sex>男</sex>
<age>22</age>
</student>
</stus>
java: 对应类来描述
Student{
stuNo, name, age,sex
}
List<Student> students;
Student[] students;
java对象与xml之间的转换:
-
把xml中的数据读取出来, 变成一个一个对象 xml的读操作
-
把java对象转换为xml,保存到xml文件 xml写操作
需要第三方的jar: dom4j
Dom4j 是一个开源的 XML 解析框架,它基于 Java 的 sax 解析器和 jaxp 解析器开发,提供了灵活简便、性能优良、扩展性强的 XML 解析和生成功能。
帮助手册:dom4j 1.6.1 API
Dom4J通过SAXReader对象加载并解析xml文件,把它转换为内存中的Document对象,接着对Document对象中的元素进行添加、更新和删除操作,并且通过XMLWriter对象把修改后的Document对象保存到xml文件中。
加载第三方jar:
1.在项目中创建一个lib文件夹
2.把第三方jar拷贝到lib目录
3.解压jar
Dom4J核心对象:
- SAXReader: xml解析器
创建SAXReader对象, 无参构造方法
调用read(xml文件资源) 读取并解析xml, 得到Document对象
- Document: xml文档
调用Element getRootElement() 得到根标签对象
- Element: 标签对象
获取第一个子标签: Element element(标签名)
获取所有的子标签: List elements(标签名)
获取属性: Attribute attribute(属性名)
获取标签的内容: elementText()
获取属性的值: attributeValue()
登录
客户端实现
private void login() {
System.out.println("\n\n------------登录操作-------------");
System.out.print("请输入用户名:");
String username = input.next();
System.out.print("请输入密码:");
String password = input.next();
try (
Socket socket = new Socket("127.0.0.1", 8888);
//对象IO流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
) {
//HashMap对象: key, value
HashMap<String, Object> map = new HashMap<>();
map.put("op", OptionEnum.LOGIN.name());
map.put("data", new User(username, password));
oos.writeObject(map);//接受服务器端响应
//String result = br.readLine();
Map rsMap = (Map) ois.readObject();
if (ResultEnum.SUCCESS.name().equals(rsMap.get("rs"))) {
System.out.println("!!【友情提示】!!登录成功!");
//显示二级菜单
showSeceondMenu();
} else {
System.out.println("!!【友情提示】!!用户名或者密码错误!");
//显示一级菜单
showFirstMenu();
}
} catch (Exception e) {
e.printStackTrace();
}
}
服务器端实现
在服务器端,由于我们需要反复连接客户端,所以在服务器端创建一个死循环,能够保证多次连接客户端,也就是一对多的连接,然后创建一个ServerThread来简化服务器的启动工程,在这个线程里实现系统的功能。
NovelServer.java:
public class NovelServer {
public static void main(String[] args){
try {
ServerSocket serverSocket = new ServerSocket(8888);
while(true){
Socket socket = serverSocket.accept();
System.out.println("有一个客户端连接了....");
//创建一个线程来处理客户的请求,只要有一个客户端的请求过来,就创建一个线程过来处理
new ServerThread(socket).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
ServerThread.java,登录功能的实现:
private void doLogin(Map map, ObjectOutputStream oos) throws DocumentException {
Map rsMap=new HashMap();
rsMap.put("rs",ResultEnum.FAIL.name());
User userMap=(User)map.get("data");
for (User user:users) {
if(user.getUsername().equals(userMap.getUsername()) && user.getPassword().equals(userMap.getPassword())){
rsMap.put("rs",ResultEnum.SUCCESS.name());
break;
}}
try {
oos.writeObject(rsMap);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
代码完善
-
创建静态代码块,实现,在系统一启动就开始解析xml文件中存储的用户信息,来判断用户是否能够登录成功
-
创建一级菜单和二级菜单
ServerThread中的static静态代码块,用户信息保存: 集合中: 使用User类封装一个用户所有信息 :
import java.io.Serializable;
public class User implements Serializable {
private int UserId;
private String username;
private String password;public void setPassword(String password) {
this.password = password;
}public void setUserId(int userId) {
UserId = userId;
}public void setUsername(String username) {
this.username = username;
}public int getUserId() {
return UserId;
}public String getPassword() {
return password;
}public String getUsername() {
return username;
}public User(int UserId,String username, String password){
this.UserId=UserId;
this.username=username;
this.password=password;
}public User(String username, String password){
this.username=username;
this.password=password;
}public User(){}
}
static {
SAXReader saxReader=new SAXReader();
Document document= null;
try {
System.out.println("解析xml");
document = saxReader.read("user.xml");
Element rootEle=document.getRootElement();
List<Element> UserElements = rootEle.elements("user");
for (Element UserEle : UserElements) {
String username = UserEle.elementText("username");
String pwd = UserEle.elementText("pwd");
int userId = Integer.parseInt(UserEle.attributeValue("userId"));
User user=new User(userId,username,pwd);
users.add(user);
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}}
异常:
解决方案:
项目登录功能控制台的实现 :
注册
注册流程与登录流程相似:
登录: 读取user.xml文件
注册: 往user.xml添加数据
- OutputFormat: 设置xml的格式: 有两种格式: 压缩(所有的标签在一行,没有缩进) createCompactFormat(), 格式化(有缩进) createPrettyPrint()
- XMLWriter: 往xml写入内容
private void doRegister(Map map, ObjectOutputStream oos) throws DocumentException, IOException {
Map rsMap=new HashMap();
User userMap=(User)map.get("data");
userMap.setUserId(users.size()+1);
//修改xml文件
SAXReader saxReader=new SAXReader();
Document document=saxReader.read("user.xml");
Element rootElement= document.getRootElement();
//添加子标签
Element newUserELe=rootElement.addElement("user");
//给user标签添加一个属性
newUserELe.addAttribute("userId",userMap.getUserId()+"");
//添加子标签
newUserELe.addElement("username").addText(userMap.getUsername());
newUserELe.addElement("pwd").addText(userMap.getPassword());
//把修改Document对象写到文件中
//OutputFormat outputFormat = OutputFormat.createCompactFormat(); //压缩模式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");
//XMLWriter 把Document对象写到文件中
XMLWriter xmlWriter=new XMLWriter(new FileWriter("user.xml"),outputFormat);
//写
xmlWriter.write(document);
xmlWriter.close();//数据校验
for (User user:users) { //判断用户名是否存在,用户名是否为空
if(user.getUsername().equals(userMap.getUsername()) || user.getUsername()==null){
rsMap.put("rs",ResultEnum.FAIL.name());
return;
}
}
users.add(userMap);
rsMap.put("rs",ResultEnum.SUCCESS.name());
try {
oos.writeObject(rsMap);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
在线阅读
小说列表查询
小说信息保存在服务器端的xml文件中, 客户端查询小说列表, 需要发送请求, 服务器把信息返回给客户端,同样的思路,创建一个静态代码块,解析book.xml文件。
static:
static {
SAXReader saxReader=new SAXReader();
Document document= null;
try {
System.out.println("解析xml");
document = saxReader.read("book.xml");
Element rootEle=document.getRootElement();
List<Element> BookElements = rootEle.elements("book");
for (Element BookEle : BookElements) {
String name = BookEle.elementText("name");
String author = BookEle.elementText("author");
String description = BookEle.elementText("description");
String type = BookEle.elementText("type");
String path = BookEle.elementText("path");
int bookId = Integer.parseInt(BookEle.attributeValue("bookId"));
Book book=new Book(bookId,name,author,type,description,path);
bookList.add(book);
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
ServerThread.java:
private void doNovelList(ObjectOutputStream oos) throws IOException {
Map map=new HashMap<>();
map.put("books",bookList);
oos.writeObject(map);
oos.flush();
}
Cilent:
private void novelList() {
System.out.println("--------------小说列表-------------\n\n");
//发送请求,查询
try(
Socket socket = new Socket("127.0.0.1",8888);
//对象IO流
ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
){
//HashMap对象: key, value
HashMap<String,Object> map=new HashMap<>();
map.put("op",OptionEnum.LIST.name());
oos.writeObject(map);//接受服务器端响应
Map rsMap=(Map) ois.readObject();
bookList=(List<Book>) rsMap.get("books");
//显示小说列表
System.out.println("================================");
System.out.println("序号\t\t书名\t\t作者\t\t类型\t\t描述");
if(bookList==null || bookList.isEmpty()){
System.out.println("【友情提示】 没有小说!^_^");
}else {
for (int i = 0; i < bookList.size(); i++) {
Book book=bookList.get(i);
System.out.println((i+1)+"\t\t"+book.getName()+"\t\t"+book.getAuthor()+"\t\t"+book.getType()+"\t\t"+book.getDescription());
}
}
System.out.println("================================");
showSeceondMenu();
}catch (Exception e){
e.printStackTrace();
}
}
运行结果:
在线小说阅读: 分页查询
客户端思路:
先显示小说列表 1. 天龙八部 2.…
让用户选择阅读的小说序号, 获取对应的小说名
发送请求到服务器 默认第一页
显示小说内容
Cilen:
private List<Book> bookList;
int page = 1;
Boolean isLast=false;public void sendToServer(String bookName) {
try (
Socket socket = new Socket("127.0.0.1", 8888);
//对象IO流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
) {
//HashMap对象: key, value
HashMap<String, Object> map = new HashMap<>();
map.put("op", OptionEnum.ON_LINE_READ.name());
map.put("name", bookName);
map.put("page", page);
oos.writeObject(map);//接受服务器端响应
Map rsMap = (Map) ois.readObject();
String content = (String) rsMap.get("data");
System.out.println(content);
if(content==""){
isLast=true;
}
} catch (Exception e) {
e.printStackTrace();
}
}private void showPage(String bookName){
System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println("0.上一页\t1.下一页\t2.评论\t3.返回二级菜单");
System.out.print("请输入:");
int num = input.nextInt();
switch (num) {
case 0:
if (page > 1) {
page--;
sendToServer(bookName);
} else {
System.out.println("【友情提示】 已经是第一页了!!!");
}
break;
case 1:
if(isLast){
System.out.println("【友情提示】 已经是最后一页了!!!");
return;
}else{
page++;
sendToServer(bookName);
}
break;
case 2:
comments();
showPage(bookName);
break;
case 3:
showSeceondMenu();
return;
}
showPage(bookName);
}
ServerThread:
private String getPathByName(String bookName){
String path="";
for (Book book : bookList) {
if(bookName.equals(book.getName())){
path=book.getPath();
break;
}
}
return path;
}private void doReadLine(Map map, ObjectOutputStream oos){
String name=(String) map.get("name");
int page=(Integer) map.get("page");
String path=getPathByName(name);
//分页读取
try(
FileReader fr=new FileReader(path);
){
int limit = (page-1)*1000;
fr.skip(limit);
int i = 0;
StringBuffer content = new StringBuffer("");
int data = -1;
while(i < 1000 && (data = fr.read()) != -1){
i++;
content.append((char)data);
}
Map rsMap = new HashMap();
rsMap.put("data",content.toString());
oos.writeObject(rsMap);
oos.flush();
}catch (IOException e){
e.printStackTrace();
}}
运行效果:
下载
服务流程:
代码实现:
Cilent:
private void download() {
String bookName = chooseNovel();
try (
Socket socket = new Socket("127.0.0.1", 8888);
//对象IO流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
FileWriter fw = new FileWriter("E:\\"+bookName+".txt");
) {
HashMap<String, Object> map = new HashMap<>();
map.put("op", OptionEnum.DOWNLOAD.name());
map.put("name", bookName);
oos.writeObject(map);//接受服务器端响应
//String result = br.readLine();
Map rsMap = (Map) ois.readObject();
String content = (String) rsMap.get("data");
//写到客户端硬盘上面,IO流
fw.write(content);
fw.flush();
if (ResultEnum.SUCCESS.name().equals(rsMap.get("rs"))) {
System.out.println("【友情提示】下载成功!");
showSeceondMenu();
}
} catch (Exception e) {
e.printStackTrace();
}}
ServerThread:
private void doDownLoad(Map map, ObjectOutputStream oos) {
String name=(String) map.get("name");
String path=getPathByName(name);
try(
FileReader fr=new FileReader(path);
){
StringBuffer content = new StringBuffer("");
int data = -1;
while( (data = fr.read()) != -1){
content.append((char)data);
}
Map rsMap = new HashMap();
rsMap.put("data",content.toString());
rsMap.put("rs",ResultEnum.SUCCESS.name());
oos.writeObject(rsMap);
oos.flush();
}catch (IOException e){
e.printStackTrace();
}
}
运行效果:
上传
与下载和用户注册有相似之处,二者的结合,上传文件路径时注意绝对路径和相对路径的问题!!!
Cilent:
private void upload(){
System.out.println("\n\n--------------上传小说---------------");
System.out.print("请输入小说名称:");
String bookName = input.next();
System.out.print("请输入小说作者:");
String author = input.next();
System.out.print("请输入小说类型:");
String type = input.next();
System.out.print("请输入小说描述:");
String description = input.next();
System.out.print("请输入小说路径:");
String path = input.next();
String path1="D:\\upload\\上传\\"+bookName+".txt";
String path2="E:\\upload1\\上传\\"+bookName+".txt";
System.out.println("\t请选择上传到哪个路径:");
System.out.println("\t路径1:"+path1);
System.out.println("\t路径2:"+path2);
System.out.print("请选择:");
int choose = input.nextInt();
HashMap<String, Object> map = new HashMap<>();
switch(choose){
case 1:
map.put("path",path1);
break;
case 2:
map.put("path",path2);
break;
}
File file = new File(path);
try (
Socket socket = new Socket("127.0.0.1", 8888);
//对象IO流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
FileReader fr = new FileReader(file);
) {
//HashMap对象: key, value
map.put("op", OptionEnum.UPLOAD.name());
map.put("data", new Book(bookName,author,type,description,path));
oos.writeObject(map);//接受服务器端响应
Map rsMap = (Map) ois.readObject();
String content = (String) rsMap.get("data");
if (ResultEnum.SUCCESS.name().equals(rsMap.get("rs"))) {
System.out.println("【友情提示】上传成功!");
//显示二级菜单
showSeceondMenu();
} else {
System.out.println("【友情提示】上传失败!");
//显示一级菜单
showFirstMenu();
}
} catch (Exception e) {
e.printStackTrace();
}
}
ServerThread :
private void doUpload(Map map, ObjectOutputStream oos) throws DocumentException, IOException {
Map rsMap=new HashMap();
Book bookMap=(Book)map.get("data");
String path=map.get("path").toString();
boolean flag = false;
for (Book book:bookList) {
if(book.getName().equals(bookMap.getName())){
flag=true;
break;
}
}
if(!flag){
bookMap.setBookId(bookList.size()+1);
//修改xml文件
SAXReader saxReader=new SAXReader();
Document document=saxReader.read("book.xml");
Element rootElement= document.getRootElement();
//添加子标签
Element newBookELe=rootElement.addElement("book");
//给book标签添加一个属性
newBookELe.addAttribute("bookId",bookMap.getBookId()+"");
//添加子标签
newBookELe.addElement("name").addText(bookMap.getName());
newBookELe.addElement("author").addText(bookMap.getAuthor());
newBookELe.addElement("type").addText(bookMap.getType());
newBookELe.addElement("description").addText(bookMap.getDescription());
newBookELe.addElement("path").addText(bookMap.getPath());
//把修改Document对象写到文件中
//OutputFormat outputFormat = OutputFormat.createCompactFormat(); //压缩模式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");
//XMLWriter 把Document对象写到文件中
XMLWriter xmlWriter=new XMLWriter(new FileWriter("book.xml"),outputFormat);
//写
xmlWriter.write(document);
xmlWriter.close();
//
FileReader fr=new FileReader(bookMap.getPath());
FileWriter fw=new FileWriter(path);
StringBuffer content = new StringBuffer("");
int data = -1;
while( (data = fr.read()) != -1){
content.append((char)data);
}
rsMap.put("data",content.toString());
fw.write(content.toString());
fw.close();
bookList.add(bookMap);
}
if (flag){
rsMap.put("rs",ResultEnum.FAIL.name());
}else {
rsMap.put("rs",ResultEnum.SUCCESS.name());
}
oos.writeObject(rsMap);
oos.flush();
}
运行效果:
在我们选择的上传路径文件中可找到这个作品,以及里面也有内容:
book.xml文件中也加入了这本书的信息,可进行小说列表查询、在线阅读和下载功能,都能在里面看到这本书,这样系统也就较为完善了
总结
- 整合了之前学过的知识,有复习的效果
- 增加了写项目的经验,对这部分有了一定的认识
- 这个系统还有很多未完善的部分,希望有好心人能提出意见,让我多多完善,也能多增加几个功能^_^!!!