一些註解java
@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 ""; }
處理對象封裝git
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處理代碼github
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; } }
測試代碼web
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的配置apache
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 無問題
代碼地址爲https://github.com/zhendiao/d...api
歡迎搜索關注本人與朋友共同開發的微信面經小程序【大廠面試助手】和公衆號【微瞰技術】