学习廖雪峰老师的 MVC开发原理 在这里记录一下。
 MVC:指的是model、view和controller,controller是处理业务逻辑返回view(视图)和model(数据)
 代码最主要的类Dispatcher:作用是
- 1.通过反射初始化保存
GetDispatcher的getMappings和GetDispatcher的postMappings,用于后面根据path取到对应的controller和method - 2.process方法负责调用dispatcher(继承多态)的invoke函数执行具体方法和参数的反射生成
ModelandView,最后通过模板引擎进行渲染。 
@WebServlet(urlPatterns = "/")
public class DispatcherServlet extends HttpServlet {
private final Logger logger = LoggerFactory.getLogger(getClass());
private Map<String, GetDispatcher> getMappings = new HashMap<>();
private Map<String, PostDispatcher> postMappings = new HashMap<>();
// TODO: 可指定package并自动扫描:
private List<Class<?>>
// 通过静态变量class获取Class实例,每个Class实例指向一个数据类型,包含该class的所有完整信息
controllers = List.of(IndexController.class, UserController.class);
private ViewEngine viewEngine;
/**
* 当Servlet容器创建当前Servlet实例后,会自动调用init(ServletConfig)方法
*/
// 初始化函数
@Override
public void init() throws ServletException {
logger.info("init {}...", getClass().getSimpleName());
// 把对象转换成为一个json字符串返回到前端
ObjectMapper objectMapper = new ObjectMapper();
// //反序列化的时候如果多了其他属性,不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 依次处理每个Controller:
for (Class<?> controllerClass : controllers) {
try {
// getConstructor()获取构造方法,newInstance()创建类
Object controllerInstance = controllerClass.getConstructor().newInstance();
// 依次处理每个Method:
for (Method method : controllerClass.getMethods()) {
if (method.getAnnotation(GetMapping.class) != null) {
// 处理@Get: 检查返回值类型
if (method.getReturnType() != ModelAndView.class && method.getReturnType() != void.class) {
throw new UnsupportedOperationException(
"Unsupported return type: " + method.getReturnType() + " for method: " + method);
}
// 检查参数类型是否支持
for (Class<?> parameterClass : method.getParameterTypes()) {
if (!supportedGetParameterTypes.contains(parameterClass)) {
throw new UnsupportedOperationException(
"Unsupported parameter type: " + parameterClass + " for method: " + method);
}
}
String[] parameterNames = Arrays.stream(method.getParameters()).map(p -> p.getName())
.toArray(String[]::new);
String path = method.getAnnotation(GetMapping.class).value();
logger.info("Found GET: {} => {}", path, method);
this.getMappings.put(path, new GetDispatcher(controllerInstance, method, parameterNames,
method.getParameterTypes()));
} else if (method.getAnnotation(PostMapping.class) != null) {
// 处理@Post:
if (method.getReturnType() != ModelAndView.class && method.getReturnType() != void.class) {
throw new UnsupportedOperationException(
"Unsupported return type: " + method.getReturnType() + " for method: " + method);
}
Class<?> requestBodyClass = null;
for (Class<?> parameterClass : method.getParameterTypes()) {
if (!supportedPostParameterTypes.contains(parameterClass)) {
if (requestBodyClass == null) {
requestBodyClass = parameterClass;
} else {
throw new UnsupportedOperationException("Unsupported duplicate request body type: "
+ parameterClass + " for method: " + method);
}
}
}
String path = method.getAnnotation(PostMapping.class).value();
logger.info("Found POST: {} => {}", path, method);
this.postMappings.put(path, new PostDispatcher(controllerInstance, method,
method.getParameterTypes(), objectMapper));
}
}
} catch (ReflectiveOperationException e) {
throw new ServletException(e);
}
}
// 创建ViewEngine:
this.viewEngine = new ViewEngine(getServletContext());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp, this.getMappings);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp, this.postMappings);
}
private void process(HttpServletRequest req, HttpServletResponse resp,
Map<String, ? extends AbstractDispatcher> dispatcherMap) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
String path = req.getRequestURI().substring(req.getContextPath().length());
AbstractDispatcher dispatcher = dispatcherMap.get(path);
if (dispatcher == null) {
resp.sendError(404);
return;
}
ModelAndView mv = null;
try {
mv = dispatcher.invoke(req, resp);
} catch (ReflectiveOperationException e) {
throw new ServletException(e);
}
if (mv == null) {
return;
}
if (mv.view.startsWith("redirect:")) {
resp.sendRedirect(mv.view.substring(9));
return;
}
PrintWriter pw = resp.getWriter();
this.viewEngine.render(mv, pw);
pw.flush();
}
private static final Set<Class<?>> supportedGetParameterTypes = Set.of(int.class, long.class, boolean.class,
String.class, HttpServletRequest.class, HttpServletResponse.class, HttpSession.class);
private static final Set<Class<?>> supportedPostParameterTypes = Set.of(HttpServletRequest.class,
HttpServletResponse.class, HttpSession.class);
}
具体的分发类
abstract class AbstractDispatcher {
  public abstract ModelAndView invoke(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ReflectiveOperationException;
}
class GetDispatcher extends AbstractDispatcher {
  final Object instance;
  final Method method;
  final String[] parameterNames;
  final Class<?>[] parameterClasses;
  public GetDispatcher(Object instance, Method method, String[] parameterNames, Class<?>[] parameterClasses) {
    super();
    this.instance = instance;
    this.method = method;
    this.parameterNames = parameterNames;
    this.parameterClasses = parameterClasses;
  }
  @Override
  public ModelAndView invoke(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ReflectiveOperationException {
    Object[] arguments = new Object[parameterClasses.length];
    for (int i = 0; i < parameterClasses.length; i++) {
      String parameterName = parameterNames[i];
      Class<?> parameterClass = parameterClasses[i];
      if (parameterClass == HttpServletRequest.class) {
        arguments[i] = request;
      } else if (parameterClass == HttpServletResponse.class) {
        arguments[i] = response;
      } else if (parameterClass == HttpSession.class) {
        arguments[i] = request.getSession();
      } else if (parameterClass == int.class) {
        arguments[i] = Integer.valueOf(getOrDefault(request, parameterName, "0"));
      } else if (parameterClass == long.class) {
        arguments[i] = Long.valueOf(getOrDefault(request, parameterName, "0"));
      } else if (parameterClass == boolean.class) {
        arguments[i] = Boolean.valueOf(getOrDefault(request, parameterName, "false"));
      } else if (parameterClass == boolean.class) {
        arguments[i] = Boolean.valueOf(getOrDefault(request, parameterName, "false"));
      } else if (parameterClass == String.class) {
        arguments[i] = getOrDefault(request, parameterName, "");
      } else {
        throw new RuntimeException("Missing handler for type: " + parameterClass);
      }
    }
    return (ModelAndView) this.method.invoke(this.instance, arguments);
  }
  private String getOrDefault(HttpServletRequest request, String name, String defaultValue) {
    String s = request.getParameter(name);
    return s == null ? defaultValue : s;
  }
}
class PostDispatcher extends AbstractDispatcher {
  final Object instance;
  final Method method;
  final Class<?>[] parameterClasses;
  final ObjectMapper objectMapper;
  public PostDispatcher(Object instance, Method method, Class<?>[] parameterClasses, ObjectMapper objectMapper) {
    this.instance = instance;
    this.method = method;
    this.parameterClasses = parameterClasses;
    this.objectMapper = objectMapper;
  }
  @Override
  public ModelAndView invoke(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ReflectiveOperationException {
    Object[] arguments = new Object[parameterClasses.length];
    for (int i = 0; i < parameterClasses.length; i++) {
      Class<?> parameterClass = parameterClasses[i];
      if (parameterClass == HttpServletRequest.class) {
        arguments[i] = request;
      } else if (parameterClass == HttpServletResponse.class) {
        arguments[i] = response;
      } else if (parameterClass == HttpSession.class) {
        arguments[i] = request.getSession();
      } else {
        BufferedReader reader = request.getReader();
        arguments[i] = this.objectMapper.readValue(reader, parameterClass);
      }
    }
    return (ModelAndView) this.method.invoke(instance, arguments);
  }
}定义的一个controller样例
public class UserController {
  private Map<String, User> userDatabase = new HashMap<>() {
    {
      List<User> users = List.of( //
          new User("bob@example.com", "bob123", "Bob", "This is bob."),
          new User("tom@example.com", "tomcat", "Tom", "This is tom."));
      users.forEach(user -> {
        put(user.email, user);
      });
    }
  };
  @GetMapping("/signin")
  public ModelAndView signin() {
    return new ModelAndView("/signin.html");
  }
  @PostMapping("/signin")
  public ModelAndView doSignin(SignInBean bean, HttpServletResponse response, HttpSession session)
      throws IOException {
    User user = userDatabase.get(bean.email);
    if (user == null || !user.password.equals(bean.password)) {
      response.setContentType("application/json");
      PrintWriter pw = response.getWriter();
      pw.write("{\"error\":\"Bad email or password\"}");
      pw.flush();
    } else {
      session.setAttribute("user", user);
      response.setContentType("application/json");
      PrintWriter pw = response.getWriter();
      pw.write("{\"result\":true}");
      pw.flush();
    }
    return null;
  }
  @GetMapping("/signout")
  public ModelAndView signout(HttpSession session) {
    session.removeAttribute("user");
    return new ModelAndView("redirect:/");
  }
  @GetMapping("/user/profile")
  public ModelAndView profile(HttpSession session) {
    User user = (User) session.getAttribute("user");
    if (user == null) {
      return new ModelAndView("redirect:/signin");
    }
    return new ModelAndView("/profile.html", "user", user);
  }
}                










