您的位置:首页 > 编程语言 > Java开发

javaweb servlet实现简单的mvc分发请求

2017-12-07 10:11 218 查看
自定义servlet请求分发,模拟mvc,视图采用freemarker2.3.27

1).创建注解

标记控制器注解Controller

仅仅起到标记的作用,没有什么具体的作用^_^

package com.fkt.core.annotation;

import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记控制器
* @author xuzhen
*
*/
@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {

}


标记映射注解RequestMapping

value就是用来存储请求Url,用来分发请求用的

package com.fkt.core.annotation;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记url
* @author xuzhen
*
*/
@Target({ TYPE, METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
/**
* 路径映射值
* @return
*/
String value() default "";
}


2).定义实体类

存储视图和数据的实体类ModelAndView

package com.fkt.core.entity;

import java.util.HashMap;
import java.util.Map;

/**
* 包含视图和数据的实体类,主要用于freemarker渲染使用
* @author xuzhen
*
*/
@SuppressWarnings({"rawtypes","unchecked"})
public class ModelAndView {
//视图名称
private String viewName = null;
//模板根容器
private Map root = null;
public ModelAndView() {
root = new HashMap();
}
public ModelAndView(String viewName) {
this();
this.viewName=viewName;
}
public String getViewName() {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
public Map getRoot() {
return root;
}
/**
* 增加数据
* @param key
* @param value
*/
public void addObject(Object key,Object value) {
root.put(key, value);
}
}


路径映射具体信息的实体类URIInfo

Method是反射包里的一个类,代表类的方法,有点类似c++的方法指针,想具体了解的话,就去看看java的反射吧^_^!

package com.fkt.core.entity;

import java.lang.reflect.Method;

/**
* uri的实体类,包含uri对应的控制器和控制器方法
* @author xuzhen
*
*/
public class URIInfo {
//控制器键
private String controllerId;
//控制器方法
private Method uriMethod;
public URIInfo() {}
public URIInfo(String controllerId,Method uriMethod) {
this.controllerId=controllerId;
this.uriMethod=uriMethod;
}
public String getControllerId() {
return controllerId;
}
public void setControllerId(String controllerId) {
this.controllerId = controllerId;
}
public Method getUriMethod() {
return uriMethod;
}
public void setUriMethod(Method uriMethod) {
this.uriMethod = uriMethod;
}

}


3). 编写反射工具类

根据注解把控制器添加到容器,根据注解存储映射的具体信息(映射路径,控制器方法)

package com.fkt.core.tool;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.fkt.core.annotation.Controller;
import com.fkt.core.annotation.RequestMapping;
import com.fkt.core.entity.URIInfo;

/**
* 反射相关工具类
* @author xuzhen
*
*/
public abstract class ReflexUtils {
/**
* 根据包名反射解析所有的控制器
* @param packageName
* @return
* @throws URISyntaxException
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Map<String,Object> analysisController(String packageName) throws URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException{
Map<String,Object> controllersMap = new HashMap<String,Object>();
ClassLoader classLoader = ReflexUtils.class.getClassLoader();
String packageDirectory = packageName.replace(".", "/");
File directory = new File(classLoader.getResource(packageDirectory).toURI());
for(File file : directory.listFiles()) {
String fName = file.getName();
if(!fName.endsWith(".class")) {
continue;
}
fName = fName.substring(0, fName.length() - 6);
String className = packageName+"."+fName;
Class cl = classLoader.loadClass(className);
//检查解析包中的类是否带有Controller注解,没有注解不往容器中添加实例
Annotation controllerAnnotation = cl.getAnnotation(Controller.class);
if(controllerAnnotation!=null) {
controllersMap.put(UUID.randomUUID().toString(), cl.newInstance());
}
}
return controllersMap;
}
/**
* 解析控制器上和方法上的RequestMapping注解,并存储对应的方法到容器
* @param controllersMap
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Map<String,URIInfo> analysisURIByController(Map<String,Object> controllersMap){
Map<String,URIInfo> uriInfosMap = new HashMap<String,URIInfo>();
for(String controllerId : controllersMap.keySet()) {
Object controller = controllersMap.get(controllerId);
Class controllerClass = controller.getClass();
String uriPrefix = "";
//解析类controller上的ReqestMapping注解
Annotation cRequestMappingAnnotation = controllerClass.getAnnotation(RequestMapping.class);
if(cRequestMappingAnnotation!=null) {
RequestMapping requestMapping = (RequestMapping)cRequestMappingAnnotation;
uriPrefix = requestMapping.value();
}
Method[] controllerMethods = controllerClass.getMethods();
for(Method controllerMethod : controllerMethods) {
Annotation mRequestMappingAnnotation = controllerMethod.getAnnotation(RequestMapping.class);
if(mRequestMappingAnnotation!=null) {
RequestMapping requestMapping = (RequestMapping)mRequestMappingAnnotation;
String uri = uriPrefix+requestMapping.value();
URIInfo uriInfo = new URIInfo(controllerId, controllerMethod);
uriInfosMap.put(uri, uriInfo);
}
}
}
return uriInfosMap;
}
}


4). 定义视图解析器,解析freemarker页面

package com.fkt.core.resolver;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;

import javax.servlet.http.HttpServletResponse;

import com.fkt.core.entity.ModelAndView;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;

/**
* 简单的freemarker模板处理引擎
* @author xuzhen
*
*/
public class FreemarkerViewResolver {
private Configuration cfg = null;
private String defaultEncoding = "UTF-8";

public FreemarkerViewResolver() {

}

public FreemarkerViewResolver(String defaultEncoding) {
this.defaultEncoding=defaultEncoding;
}
/**
* 初始化freemarker引擎
* @param directory
* @throws IOException
*/
public void init(URI viewDirectory) throws IOException {
cfg = new Configuration(Configuration.VERSION_2_3_27);
cfg.setDefaultEncoding(defaultEncoding);
cfg.setDirectoryForTemplateLoading(new File(viewDirectory));
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
}
//视图解析方法
public void resolver(ModelAndView mav,HttpServletResponse response) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
Template template = cfg.getTemplate(mav.getViewName());
Writer out = response.getWriter();
template.process(mav.getRoot(), out);
out.flush();
}
}


5). 定义请求分发servlet

package com.fkt.core;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fkt.core.entity.ModelAndView;
import com.fkt.core.entity.URIInfo;
import com.fkt.core.resolver.FreemarkerViewResolver;
import com.fkt.core.tool.ReflexUtils;
/**
* freemarker测试核心分发控制器
* @author xuzhen
*
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1762792866529445537L;
//定义存储所有的控制器的容器
private Map<String,Object> controllersMap = null;
//定义存储uri信息容器
private Map<String,URIInfo> uriInfosMap = null;
//创建模板引擎
private FreemarkerViewResolver viewResolver = null;
//编码默认使用utf-8
private String defaultCharacterEncoding = "UTF-8";
@Override
public void init() throws ServletException {
defaultCharacterEncoding = getInitParameter("characterEncoding");
String mvcPackage = getInitParameter("mvcPackage");
String viewDirectory = getInitParameter("viewDirectory");
try {
controllersMap = ReflexUtils.analysisController(mvcPackage);
uriInfosMap = ReflexUtils.analysisURIByController(controllersMap);
viewResolver = new FreemarkerViewResolver(defaultCharacterEncoding);
viewResolver.init(getServletContext().getResource(viewDirectory).toURI());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding(defaultCharacterEncoding);
resp.setCharacterEncoding(defaultCharacterEncoding);
String uri = req.getRequestURI().replace(req.getServletContext().getContextPath(), "");
URIInfo uriInfo = uriInfosMap.get(uri);
try {
Object mavObject = uriInfo.getUriMethod().invoke(controllersMap.get(uriInfo.getControllerId()), req,resp);
if(mavObject!=null) {
viewResolver.resolver((ModelAndView) mavObject, resp);
return;
}
} catch (Exception e) {
//处理最外层捕捉错误,并抛到前台
e.printStackTrace(resp.getWriter());
return;
}
//没有正确的处理时的输出
resp.getWriter().println("^_^ error!");
resp.getWriter().flush();
}
@Override
public void destroy() {

}
}


6). 使用

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>freemarker-test</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.fkt.core.DispatcherServlet</servlet-class>
<!-- 要扫描的控制器包 -->
<init-param>
<param-name>mvcPackage</param-name>
<param-value>com.fkt.web.controller</param-value>
</init-param>
<!-- 视图所在路径 -->
<init-param>
<param-name>viewDirectory</param-name>
<param-value>/WEB-INF/views</param-value>
</init-param>
<!-- 制定编码 -->
<init-param>
<param-name>characterEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>


TestController

package com.fkt.web.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fkt.core.annotation.Controller;
import com.fkt.core.annotation.RequestMapping;
import com.fkt.core.entity.ModelAndView;

@Controller
public class TestController {
@RequestMapping("/")
public ModelAndView index(HttpServletRequest request,HttpServletResponse response) throws IOException {
ModelAndView mav = new ModelAndView("index.ftl");
mav.addObject("name", "欢迎进入首页!");
return mav;
}

}


index.ftl

<!DOCTYPE HTML>
<html>
<head>
<title>首页</title>
<meta charset="utf-8"/>
</head>
<body>
<h1>${name!""}</h1>
</body>
</html>


代码下载

下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  servlet