手写springmvc
本次手写框架是为了更好的理解springmvc底层是如何运作的,参考springboot的思路,通过注解和反射来完成,这里需要导入三个jar包是为了json格式字符串的转换。
整体结构设计
包结构
执行流程图
第一步将请求和响应封装成类
HttpServletRequest封装了url属性
package javax.http;
public class HttpServletRequest {
// /register,/login
String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
HttpServletResponse封装了执行结果
package javax.http;
public class HttpServletResponse {
// controller执行的结果
String responseBody;
public String getResponseBody() {
return responseBody;
}
public void setResponseBody(String responseBody) {
this.responseBody = responseBody;
}
}
第二步定义注解用于扫描类和方法
Controller注解
package org.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
RestController注解
package org.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//controller返回的是对象
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RestController {
}
RequestMapping的value属性是为了获取注解参数
package org.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value();
}
第三步定义一个响应数据的实体类和两个处理器
OrderEntity类
定义一个实体类用来封装要相应的参数
package com.tedu.mall.controller;
public class OrderEntity {
String id;
int price;
public OrderEntity(String id, int price) {
super();
this.id = id;
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
UserController类
加注解Controller和RequestMapping,用于通过访问返回结果封装在HttpServletResponse的对象中
package com.tedu.mall.controller;
import javax.http.HttpServletResponse;
import org.springmvc.annotation.Controller;
import org.springmvc.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/register")
public HttpServletResponse register() {
HttpServletResponse response=new HttpServletResponse();
response.setResponseBody("register success");
return response;
}
@RequestMapping("/login")
public HttpServletResponse login() {
HttpServletResponse response=new HttpServletResponse();
response.setResponseBody("login success");
return response;
}
}
OrderController类
加注解RestController和RequestMapping,用于通过访问返回结果封装在OrderEntity对象中返回给客户端
package com.tedu.mall.controller;
import org.springmvc.annotation.RequestMapping;
import org.springmvc.annotation.RestController;
@RestController
public class OrderController {
@RequestMapping("/getOrder")
public OrderEntity getOrder() {
OrderEntity orderEntity = new OrderEntity("202008120001", 9000);
return orderEntity;
}
}
第四步编写一个ControllerDefinition实体类用于封装每一个controller中的方法。
package org.springmvc;
//封装controller
public class ControllerDefinition {
String url;// /register /login
String controllerName;// UserController
String methodName;// register,login
Boolean isJson;
public ControllerDefinition(String url, String controllerName, String methodName, Boolean isJson) {
super();
this.url = url;
this.controllerName = controllerName;
this.methodName = methodName;
this.isJson = isJson;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getControllerName() {
return controllerName;
}
public void setControllerName(String controllerName) {
this.controllerName = controllerName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Boolean getIsJson() {
return isJson;
}
public void setIsJson(Boolean isJson) {
this.isJson = isJson;
}
}
第五步编写一个WebApplictionContext类用于扫描所有的controller并封装在map中
package org.springmvc;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.springmvc.annotation.RequestMapping;
import org.springmvc.annotation.RestController;
public class WebApplictionContext {
// /register,{/register,UserController,register,false}
// /login,{/login,UserController,login,false}
public static HashMap UrlMapping = new HashMap<>();
public void init() throws Throwable {
// 扫描所有的controller
String[] controllerNames = { "com.tedu.mall.controller.UserController" ,
"com.tedu.mall.controller.OrderController"};
for (String controllerName : controllerNames) {
Class clazz = Class.forName(controllerName);
// 得到所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// 判断方法有没有加requestMapping注解
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
if (requestMapping != null) {
// 得到url
String url = requestMapping.value();
// 创建ControllerDefinition
String methodName = method.getName();
boolean isJson = false;
//判断这个类有没有加@restController
RestController restController=(RestController) clazz.getAnnotation(RestController.class);
if (restController!=null) {
isJson=true;
}
ControllerDefinition controllerDefinition = new ControllerDefinition(url, controllerName,
methodName, isJson);
// 把controllerDefinition放到UrlMapping
UrlMapping.put(url, controllerDefinition);
}
}
}
}
}
第六步编写一个DispatcherServlet前端处理器
package org.springmvc;
import java.lang.reflect.Method;
import javax.http.HttpServletRequest;
import javax.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DispatcherServlet {
WebApplictionContext context = new WebApplictionContext();
public DispatcherServlet() throws Throwable {
context.init();
}
public HttpServletResponse doDispatch(HttpServletRequest request) throws Throwable {
// 到webApplicationContext.urlMapping找到controller
ControllerDefinition controllerDefinition = context.UrlMapping.get(request.getUrl());
// 调用controller中的方法
String controllerName = controllerDefinition.getControllerName();
String methodName = controllerDefinition.getMethodName();
Class clazz = Class.forName(controllerName);
Object controllerObject = clazz.newInstance();
Method method = clazz.getDeclaredMethod(methodName);
// OrderController.getOrder()返回的是OrderEntity
// UserController.register()/login()返回的是response
HttpServletResponse response = null;
if (controllerDefinition.isJson == false) {
// userController
response = (HttpServletResponse) method.invoke(controllerObject);
} else {
// orderController
Object result = method.invoke(controllerObject);
// 用jackson框架把result转成json字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(result);
response = new HttpServletResponse();
response.setResponseBody(jsonString);
}
return response;
}
}
第七步编写一个WebServer服务器
package org.springmvc;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
import javax.http.HttpServletRequest;
import javax.http.HttpServletResponse;
import javax.xml.ws.http.HTTPBinding;
//实现tomcat的核心功能
public class WebServer {
public static void main(String[] args) throws Throwable{
//监听端口号
ServerSocket serverSocket=new ServerSocket(8080);
System.out.println("webServer运行了");
while(true) {
Socket socket=serverSocket.accept();
HttpRequestThread thread=new HttpRequestThread(socket);
thread.start();
}
}
static class HttpRequestThread extends Thread{
Socket socket;
public HttpRequestThread(Socket socket) {
super();
this.socket = socket;
}
@Override
public void run() {
//接收浏览器发过来的请求
try {
InputStream inputStream=socket.getInputStream();
InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
String requestLine=bufferedReader.readLine();
System.out.println(requestLine);
// get /login
//分词,
StringTokenizer stringTokenizer=new StringTokenizer(requestLine);
String requestMethod=stringTokenizer.nextToken();
System.out.println("requestMethod="+requestMethod);
String url=stringTokenizer.nextToken();
System.out.println("url="+url);
//把浏览器发过来的请求交给dispatcherServlet
HttpServletRequest request=new HttpServletRequest();
request.setUrl(url);
DispatcherServlet dispatcherServlet=new DispatcherServlet();
HttpServletResponse response=dispatcherServlet.doDispatch(request);
System.out.println("controller执行的结果:"+response.getResponseBody());
//把controller的结果返回给浏览器
//响应行
String responseLine="HTTP/1.1 200 ok \r\n";
//响应头
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append("Content-Type:text/html\r\n");
String responseBody=response.getResponseBody();
stringBuilder.append("Content-Length:"+responseBody.length()+"\r\n");
stringBuilder.append("\r\n");
//响应体
OutputStream outputStream=socket.getOutputStream();
outputStream.write(responseLine.getBytes());
outputStream.write(stringBuilder.toString().getBytes());
outputStream.write(responseBody.getBytes());
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}