Jetty上的简单MVC容器设计
来源:互联网 发布:统赢编程教程 编辑:程序博客网 时间:2024/06/03 09:25
最近写了个简单的类似SpringMVC的小容器,在Jetty中运行,在这里分享一下。
主要用到的第三方JAR包如下:
工程代码结构如下:
我设计的思想来源于SpringMVC,也采用注解和反射的方式加载类,用freemarker作为Model和View的合并工具。
代码如下(内有中文注释):
package org.kitty.web;import org.kitty.web.container.MvcContainer;import org.kitty.web.container.ServletDispatch;import org.mortbay.jetty.Server;import org.mortbay.jetty.nio.SelectChannelConnector;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Jetty容器 * @author zhaowen */public class JettyServer {private static final Logger LOG = LoggerFactory.getLogger(JettyServer.class);public void start() {// 设置SocketSelectChannelConnector connector = new SelectChannelConnector();connector.setPort(9090);// 方法1:手动设置映射关系// ServletDispatch.addDipatch("/page.action", PageServlet.class);// 方法2:直接加载具体的类// MvcContainer.loadController("org.kitty.web.IndexController");// 方法3:以扫描包的方式加载MvcContainer.scanPackage("org.kitty.web");// 设置服务器参数Server server = new Server();server.addConnector(connector);// 设置ServletHandlerserver.addHandler(ServletDispatch.getServletHandler());try {// 启动Jetty容器server.start();} catch (Exception e) {LOG.error("", e);}}public static void main(String[] args) {new JettyServer().start();}}类扫描与注解的处理如下:
package org.kitty.web.container;import java.io.File;import java.lang.reflect.Method;import org.kitty.web.annotation.Controller;import org.kitty.web.annotation.RequestMapping;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * MVC容器,用于加载Controller类 * @author zhaowen */public class MvcContainer {private static final Logger LOG = LoggerFactory.getLogger(MvcContainer.class);/** * 加载Controller * @param classname */@SuppressWarnings({ "unchecked", "rawtypes" })public static void loadController(String classname){try {// 加载指定的类Class clazz = ClassLoader.getSystemClassLoader().loadClass(classname);// 判断此类是否有Controller注解if(clazz.isAnnotationPresent(Controller.class)){// 获取此类的所有方法Method[] methods = clazz.getMethods();for(Method m : methods){// 选择有RequestMapping注解的方法if(m.isAnnotationPresent(RequestMapping.class)){RequestMapping rm = m.getAnnotation(RequestMapping.class);// 获取servlet的请求路径String path = rm.value();// 将注解的方法加入容器ServletDispatch.addMethod(path, m);// 将映射关系存入容器ServletDispatch.addDipatch(path, ServletTemplate.class);}}}} catch (ClassNotFoundException e) {LOG.error("",e);}}/** * 扫描包并加载 */public static void scanPackage(String packagefile){String root = ClassLoader.getSystemResource("").getPath();String path = root + packagefile.replace(".", "\\");File file = new File(path);String[] files = file.list();for(String f : files){if(f.endsWith("Controller.class")){MvcContainer.loadController(packagefile + "." + f.replace(".class", ""));}}}}自定义的两个注解如下,类似于Spring:
package org.kitty.web.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Controller {}
package org.kitty.web.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface RequestMapping {String value() default "";}映射关系容器:
package org.kitty.web.container;import java.lang.reflect.Method;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import org.mortbay.jetty.servlet.ServletHandler;@SuppressWarnings("rawtypes")public class ServletDispatch {// 映射关系容器private static Map<String, Class> container = new ConcurrentHashMap<String, Class>();// 调用关系容器private static Map<String, Method> invokes = new ConcurrentHashMap<String, Method>();// Jetty的Servlet处理器private static ServletHandler handler = new ServletHandler();public static ServletHandler getServletHandler() {return handler;}public static synchronized void addDipatch(String path, Class servlet) {container.put(path, servlet);// 加入到ServletHandler中handler.addServletWithMapping(servlet, path);}public static synchronized Class getDipatch(String path) {return container.get(path);}public static synchronized void addMethod(String path, Method method) {invokes.put(path, method);}public static synchronized Method getMethod(String path) {return invokes.get(path);}}由于Jetty是Servlet容器,最终的HTTP请求都转化成Servlet来处理,这里我是这样将Controller转化成Servlet的,写了一个Servlet模板:
package org.kitty.web.container;import java.io.IOException;import java.io.PrintWriter;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.kitty.web.view.HtmlTool;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * servlet容器模板,供Controller使用,反射调用Controller的注解方法 * @author zhaowen */public class ServletTemplate extends HttpServlet {private static final Logger LOG = LoggerFactory.getLogger(ServletTemplate.class);/** * */private static final long serialVersionUID = 5237184324182149493L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {// 根据当前的请求路径从容器中获取要调用的方法Method method = ServletDispatch.getMethod(req.getServletPath());if (method != null) {try {// 利用反射调用方法Object obj = method.getDeclaringClass().newInstance();method.invoke(obj, req, resp);} catch (IllegalAccessException e) {LOG.error("", e);} catch (IllegalArgumentException e) {LOG.error("", e);} catch (InvocationTargetException e) {LOG.error("", e);} catch (InstantiationException e) {LOG.error("", e);}} else {PrintWriter pw = resp.getWriter();Map<String, Object> model = new HashMap<String, Object>();model.put("content", "Template");String data = HtmlTool.getHtml(model, "index.ftl");pw.write(data);pw.flush();pw.close();}super.doGet(req, resp);}}我测试用的展示层模板是用ftl文件,语法参见freemarker:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="pragma" content="no-cache" /><meta http-equiv="cache-control" content="no-cache" /><meta http-equiv="expires" content="0" /></head> <body><h1>hello ${content}</h1></body> </html>Model与View的合并如下:
package org.kitty.web.view;import java.io.IOException;import java.io.StringWriter;import java.io.Writer;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;@SuppressWarnings("deprecation")public class HtmlTool {private static final Logger LOG = LoggerFactory.getLogger(HtmlTool.class);private static Configuration configuration;static {configuration = new Configuration();configuration.setClassForTemplateLoading(HtmlTool.class, "");}/** * 生成HTML文件 * * @param map * Data Model * @param ftl * template file * @return HTML */public static String getHtml(Map<String, Object> model, String ftl) {Template template = null;Writer out = new StringWriter();try {template = configuration.getTemplate(ftl);template.setEncoding("UTF-8");try {// merge template and datatemplate.process(model, out);} catch (TemplateException e) {LOG.error("", e);}} catch (IOException e) {LOG.error("", e);}return out.toString();}}
最后是具体的Controller类的编写了,在没有MVC时用的就是Servlet,如下:
package org.kitty.web;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.kitty.web.view.HtmlTool;/** * servlet方式处理请求 * @author zhaowen */public class PageServlet extends HttpServlet {/** * */private static final long serialVersionUID = 7200471112326637238L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {PrintWriter pw = resp.getWriter();Map<String, Object> model = new HashMap<String, Object>();model.put("content", "PageServlet");String data = HtmlTool.getHtml(model, "index.ftl");pw.write(data);pw.flush();pw.close();super.doGet(req, resp);}}
有了MVC后的写法就变了:
package org.kitty.web;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.kitty.web.annotation.Controller;import org.kitty.web.annotation.RequestMapping;import org.kitty.web.view.HtmlTool;/** * 类似于SpringMVC的例子 * @author zhaowen */@Controllerpublic class IndexController {@RequestMapping("/index.htm")public void index(HttpServletRequest req, HttpServletResponse resp)throws IOException {PrintWriter pw = resp.getWriter();// 数据层Model处理Map<String, Object> model = new HashMap<String, Object>();model.put("content", "Kitty");// 用数据和模板生成HTML文件String viewTemplate = "index.ftl";String data = HtmlTool.getHtml(model, viewTemplate);pw.write(data);pw.flush();pw.close();}@RequestMapping("/index/hello.do")public void hello(HttpServletRequest req, HttpServletResponse resp)throws IOException {PrintWriter pw = resp.getWriter();Map<String, Object> model = new HashMap<String, Object>();model.put("content", "MVC");String data = HtmlTool.getHtml(model, "index.ftl");pw.write(data);pw.flush();pw.close();}}是不是和SpringMVC的很像?
区别就在于:
// 方法1:手动设置映射关系// ServletDispatch.addDipatch("/page.action", PageServlet.class);// 方法2:直接加载具体的类// MvcContainer.loadController("org.kitty.web.IndexController");// 方法3:以扫描包的方式加载
浏览器的测试结果如下:
当然,这只是个简单的Demo,和SpringMVC比起来还差很远,不过通过这个Demo,初学者应该对Spring的运行原理有一定的认识了,而且也学会了Jetty容器的使用。
0 0
- Jetty上的简单MVC容器设计
- linux上jetty的简单使用
- Maven建立基于jetty容器的简单的web工程
- servlet容器tomcat和jetty的简单使用
- nginx/jetty在Lift-web上的简单应用配置
- 简单的php-mvc设计
- Jetty容器
- jetty容器
- IOS平台上的MVC设计模式
- spring Mvc 的 简单总结 上
- Tomcat :一个简单的Servlet容器+Spring MVC响应流程
- Servlet容器:Jetty和tomcat的比较
- JETTY嵌入式Web容器的开发
- Jetty一个开源的servlet容器
- jetty容器使用的一个错误
- 简单的有限状态机设计---上
- JavaWeb中最简单的MVC设计
- MVC设计模式的简单理解
- JS之DOM
- hdu 1506 dp
- Category延展:用于声明私有方法
- 解决ubuntu中vi不能正常使用方向键与退格键的问题
- Java中Runnable和Thread的区别
- Jetty上的简单MVC容器设计
- 大公司的边角料人才
- Django 1.5.4 专题26 Bootstrap
- python3 基础模块(随机数,bisect,匹配统计,压缩,csv,logging,getpass,configparser等模块)
- Wireless Network(2236)
- HDU 4508 湫湫系列故事——减肥记I(完全背包)
- Socket连接过程
- ubuntu 命令行界面无法显示中文解决方案
- tcp 三次握手和四次断连深入分析:连接状态和socket API的关系