1.V14(项目)
此版本完成用户注册业务操作 上一个版本我们已经将注册页面中表单提交的数据解析完毕并存入到HttpServletRequest对应属性中了 此版本我们完成DispatcherServlet处理请求的环节,增加对业务的处理。 实现: 1:新建一个包:com.webserver.controller 这个包中保存所有将来用于处理业务的类 2:在controller包中新建处理与用户数据相关的业务类:UserController 3:在UserController中添加reg()方法,用于处理用户注册逻辑 4:在DispatcherServlet处理请求的环节中,首先我们将原来判断路径使用的请求对象中的uri换成 requestURI. 原因:uri中可能表示的路径中含有参数,而不是纯请求部分了。 5:如果请求路径是/myweb/reg,则说明这次请求是reg.html页面form表单提交的请求(action决定) 那么这个请求就是要处理注册业务,因此我们实例化UserController并调用reg方法进行处理即可。
1.1项目录目
1.2Java页面
1.2.1UserController
package com.webserver.controller;
import com.webserver.core.ClientHandler;
import com.webserver.entity.User;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.URISyntaxException;
/**
* 处理与用户相关的业务操作
*/
public class UserController {
private static File rootDir;
private static File staticDir;
//表示users目录
private static File userDir;
static{
try {
rootDir = new File(
ClientHandler.class.getClassLoader()
.getResource(".").toURI()
);
staticDir = new File(rootDir,"static");
} catch (URISyntaxException e) {
e.printStackTrace();
}
userDir = new File("users");
if(!userDir.exists()){
userDir.mkdirs();
}
}
public void reg(HttpServletRequest request, HttpServletResponse response){
/*
1:获取用户在注册页面上输入的注册信息
2:将注册信息保存起来
3:给用户回馈一个注册结果页面
*/
//1
//调用getParameter时传入的参数应当与页面上表单中输入框的名字一致(输入框name属性的值)
String username = request.getParameter("username");
String password = request.getParameter("password");
String nickname = request.getParameter("nickname");
String ageStr = request.getParameter("age");
/*
添加一个判断,要求:如果上述四个信息有null值或者年龄不是数字
立刻给用户响应一个错误提示页面:reg_info_error.html
该页面居中显示一行字:注册信息输入有误,请重新注册。
正则表达式:[0-9]+
*/
if(username==null||password==null||nickname==null||ageStr==null||
!ageStr.matches("[0-9]+")){
File file = new File(staticDir,"/myweb/reg_info_error.html");
response.setContentFile(file);
return;
}
int age = Integer.parseInt(ageStr);
System.out.println(username+","+password+","+nickname+","+age);
//2
User user = new User(username,password,nickname,age);
File userFile = new File(userDir,username+".obj");
/*
判断重名,如果是已注册用户,则响应页面:have_user.html告知
该页面居中显示一行字:该用户已存在,请重新注册。
*/
if(userFile.exists()){//该文件存在则说明是重复用户
File file = new File(staticDir,"/myweb/have_user.html");
response.setContentFile(file);
return;
}
try (
FileOutputStream fos = new FileOutputStream(userFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
){
//这里序列化的是注册用户信息,因此是user对象!!!!!!!!!!!!
oos.writeObject(user);
//3
File file = new File(staticDir,"/myweb/reg_success.html");
response.setContentFile(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.2.2ClientHandler
package com.webserver.core;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.*;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* 该线程任务是负责与一个客户端进行一次HTTP交互
* 浏览器与服务端交互组从一问一答的原则。因此服务端处理一次HTTP交互,步骤如下:
* 1:解析请求(接受浏览器发送过来的请求内容)
* 2:处理请求(根据浏览器发送的请求理解其意图并进行对应的处理)
* 3:发送响应(将处理结果发送给浏览器)
*
*
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
try {
//1解析请求
HttpServletRequest request = new HttpServletRequest(socket);
HttpServletResponse response = new HttpServletResponse(socket);
//2处理请求
DispatcherServlet servlet = new DispatcherServlet();
servlet.service(request,response);
//3发送响应
response.response();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//按照HTTP协议要求,一次交互后要断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.2.3DispatcherServlet
package com.webserver.core;
import com.webserver.controller.UserController;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
/**
* 负责处理请求环节
*/
public class DispatcherServlet {
private static File rootDir;
private static File staticDir;
static{
try {
rootDir = new File(
ClientHandler.class.getClassLoader()
.getResource(".").toURI()
);
staticDir = new File(rootDir,"static");
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public void service(HttpServletRequest request, HttpServletResponse response){
//不能再直接使用uri了,因为这里可能含有参数,而参数值是用户输入的,不是固定内容
// String path = request.getUri();
String path = request.getRequestURI();
//根据请求路径判断是否为处理某个业务
if("/myweb/reg".equals(path)){
UserController controller = new UserController();
controller.reg(request, response);
}else {
File file = new File(staticDir, path);
System.out.println("资源是否存在:" + file.exists());
if (file.isFile()) {
//将请求的实际文件设置到response的正文上等待响应
response.setContentFile(file);
} else {
file = new File(staticDir, "/root/404.html");
//将404内容设置到response上等待响应
response.setStatusCode(404);
response.setStatusReason("NotFound");
response.setContentFile(file);
}
}
}
}
1.2.4WebServerApplication
package com.webserver.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* WebServer主类
* WebServer是一个Web容器,实现了Tomcat的基础功能。
* 通过本次项目我们的目标是:
* 1:理解Tomcat底层工作原理
* 2:理解HTTP协议的规定
* 3:理解SpringBoot
*/
public class WebServerApplication {
private ServerSocket serverSocket;
/**
* 初始化WebServer
*/
public WebServerApplication(){
try {
System.out.println("正在启动服务端...");
/*
当端口被其他程序占用时,这里会抛出异常:
java.net.BindException:address already in use:JVM
解决:
1:杀死该java进程(推荐)
2:重启电脑(不推荐)
3:更换端口(通常重启后还不行,说明被其他程序占用该端口了)
*/
serverSocket = new ServerSocket(8088);
System.out.println("服务端启动完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 服务端开始工作的方法
*/
public void start(){
try {
while(true) {
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接了!");
//启动一个线程处理该客户端交互
ClientHandler clientHandler = new ClientHandler(socket);
Thread thread = new Thread(clientHandler);
thread.start();
}
} catch (IOExce