简单实现 springmvc 中的请求处理
发布于: 2 小时前
自定义 MVC 框架中的一些元素
一些注解
@Documented@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Controller { String value () default "";}
@Documented@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RequestMapping { String value () default "";}
@Documented@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Service { String value () default "";}
@Documented@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface Autowired { String value () default "";}
复制代码
处理对象封装
public class Handler {
private Object controller;//Controller对应的类 private Method method;//执行业务的方法 private Pattern pattern;//uri private Map<String,Integer> paramIndexMapping;//参数和位置的映射
public Handler(Object controller, Method method, Pattern pattern) { this.controller = controller; this.method = method; this.pattern = pattern; this.paramIndexMapping = new HashMap<>(); }
public Object getController() { return controller; }
public void setController(Object controller) { this.controller = controller; }
public Method getMethod() { return method; }
public void setMethod(Method method) { this.method = method; }
public Pattern getPattern() { return pattern; }
public void setPattern(Pattern pattern) { this.pattern = pattern; }
public Map<String, Integer> getParamIndexMapping() { return paramIndexMapping; }
public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) { this.paramIndexMapping = paramIndexMapping; }}
复制代码
自定义 DisptchServelet 处理代码
public class DispatchServelet extends HttpServlet { private Properties properties = new Properties(); private List<String> classNames = new ArrayList<>(); private Map<String,Object> ioc =new HashMap<>(); private List<Handler> handlerMapping = new ArrayList<>(); @Override public void init(ServletConfig config) throws ServletException { //加载配置文件 String contextConfigLocation = config.getInitParameter("contextConfigLocation"); doLoadConfig(contextConfigLocation); //扫描相关的类,扫描注解 doScan(properties.getProperty("scanPackage")); //初始化bean,基于注解 doInstance(); //实现依赖注入 doAutoWired(); //实现处理器映射器,将url和method进行关联 initHandlerMapping(); System.out.println("mvc 初始化完成"); } //执行的是方法和url方法映射 private void initHandlerMapping() { if (ioc.isEmpty()){ return; } for (Map.Entry<String,Object> entry :ioc.entrySet()){ Class<?> aClass = entry.getValue().getClass(); if (!aClass.isAnnotationPresent(Controller.class)){ continue; } String baseUrl = ""; if (aClass.isAnnotationPresent(RequestMapping.class)){ RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class); baseUrl=requestMapping.value(); } Method[] methods= aClass.getMethods(); for (int i=0;i<methods.length;i++){ Method method = methods[i]; if (!method.isAnnotationPresent(RequestMapping.class)){ continue; } RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); String methodUrl = requestMapping.value(); String url = baseUrl+methodUrl; Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url)); Parameter[] parameters = method.getParameters(); for (int j=0;j<parameters.length;j++){ Parameter parameter = parameters[j]; if (parameter.getType().equals(HttpServletRequest.class)||parameter.getType().equals(HttpServletResponse.class)){ handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j); }else { handler.getParamIndexMapping().put(parameter.getName(),j); } } //完成方法和url的映射关系 handlerMapping.add(handler); } } } //执行注入部分,同样是做的ioc的部分功能 private void doAutoWired() { if (ioc.isEmpty()){ return; } for (Map.Entry<String,Object> entry :ioc.entrySet()){ Field[] declareFields = entry.getValue().getClass().getDeclaredFields(); for (int i=0;i<declareFields.length;i++){ Field declareField = declareFields[i]; if (!declareField.isAnnotationPresent(Autowired.class)){ continue; } Autowired autowired = declareField.getAnnotation(Autowired.class); String beanName = autowired.value(); if ("".equals(beanName.trim())){ beanName=declareField.getType().getName(); } declareField.setAccessible(true); try { //直接将这个字段的值设置为ioc中已经示例化的类, // 即是完成了ioc中的实例化交给容器来管理的情况 declareField.set(entry.getValue(),ioc.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); } }
} }
//执行的是符合要求的类的初始化,实际上是实现的一部分ioc的功能 private void doInstance() { if (classNames.size()==0){ return; } try { for (int i=0;i<classNames.size();i++){ String className = classNames.get(i); Class<?> clazz = Class.forName(className); if (clazz.isAnnotationPresent(Controller.class)){ String simpleName = clazz.getSimpleName(); String lowerFirst = lowerFirst(simpleName); Object o = clazz.newInstance(); //因为controller无别名,所以简单设置成首字母小写就行 ioc.put(lowerFirst,o); }else if (clazz.isAnnotationPresent(Service.class)){ Service service = clazz.getAnnotation(Service.class); String beanName =service.value(); if (!"".equals(beanName.trim())){ ioc.put(beanName,clazz.newInstance()); }else { beanName = lowerFirst(clazz.getSimpleName()); ioc.put(beanName,clazz.newInstance()); }
Class<?>[] interfaces = clazz.getInterfaces(); for (int j=0;j<interfaces.length;j++){ Class<?> ainterface = interfaces[j]; System.out.println(ainterface.getName()); //将实现类和接口进行绑定 ioc.put(ainterface.getName(),clazz.newInstance()); } }else { continue; } } }catch (Exception e){ e.printStackTrace(); }
}
private String lowerFirst(String className){ char[] chars = className.toCharArray(); if ('A'<chars[0]&&chars[0]<'Z'){ chars[0]+=32; } return new String(chars); } private void doScan(String basePackage) { //获取到指定包下的所有类的类名 String scanPackagePath= Thread.currentThread().getContextClassLoader().getResource("").getPath()+basePackage.replaceAll("\\.","/"); File pack = new File(scanPackagePath); File [] files = pack.listFiles(); for (File file:files){ if (file.isDirectory()){ doScan(basePackage+"."+file.getName()); }else if (file.getName().endsWith(".class")){ String className = basePackage+"."+file.getName().replaceAll(".class",""); classNames.add(className); } } } //实现加载web.xml中配置的文件的路径 private void doLoadConfig(String contextConfigLocation) { InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation); try { properties.load(inputStream); } catch (IOException e) { 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 { Handler handler = getHander(req); if (handler==null){ resp.getWriter().write("404 not found"); return; } Class<?> [] parameterTypes = handler.getMethod().getParameterTypes(); Object[] paraValues = new Object[parameterTypes.length];
Map<String,String[]> parameterMap = req.getParameterMap(); for (Map.Entry<String,String[]> param:parameterMap.entrySet()){ String value = StringUtils.join(param.getValue(),","); if (!handler.getParamIndexMapping().containsKey(param.getKey())){ continue; } //对应实际参数的位置 Integer index = handler.getParamIndexMapping().get(param.getKey()); paraValues[index]=value;
} //对应上req,和resp参数的位置 int reqIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName()); paraValues[reqIndex]=req; int respIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName()); paraValues[respIndex]=resp;
try { //实际执行的是controller中的方法 handler.getMethod().invoke(handler.getController(),paraValues); System.out.println("执行controller方法成功"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
}
private Handler getHander(HttpServletRequest req) { if (handlerMapping.isEmpty()){ return null; } String url =req.getRequestURI(); for (Handler handler:handlerMapping){ Matcher matcher = handler.getPattern().matcher(url); if (!matcher.matches()){ continue; } return handler; } return null; }
}
复制代码
测试代码
public interface DemoService {
String getName(String name);}
@Service("demoService")public class DemoServiceImpl implements DemoService { @Override public String getName(String name) { return name; }}
@Controller@RequestMapping("/demo")public class DemoController { @Autowired private DemoService demoService; @RequestMapping("/query") public String query(HttpServletRequest req, HttpServletResponse resp,String name){ return demoService.getName(name); }}
复制代码
web.xml 配置
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>com.zhao.mvcframework.servelet.DispatchServelet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>mvc.properties</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>
复制代码
mvc.properties 的配置
scanPackage=com.zhao.mvcdemo
复制代码
pom 文件的配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.zhao</groupId> <artifactId>mvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
<name>mvc Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties>
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.10</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration>
</plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> <compilerArgs>-parameters</compilerArgs> </configuration> </plugin> </plugins> </build></project>
复制代码
测试时访问具体的 http://localhost:8080/demo/query?name=zhaozhen 无问题
划线
评论
复制
发布于: 2 小时前阅读数: 2
版权声明: 本文为 InfoQ 作者【赵镇】的原创文章。
原文链接:【http://xie.infoq.cn/article/43525ca720c18bc24496212ac】。文章转载请联系作者。
赵镇
关注
还未添加个人签名 2017.12.20 加入
还未添加个人简介











评论