Customize some elements in the MVC framework

Some annotations

@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 "";
}
Copy the code

Handling object encapsulation

public class Handler { private Object controller; //Controller class 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; }}Copy the code

Custom DisptchServelet handler code

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;
    }

}
Copy the code

The test code

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); }}Copy the code

The web.xml configuration

<! 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 > < the display - the 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>Copy the code

MVC. The properties of the configuration

scanPackage=com.zhao.mvcdemo
Copy the code

Configure POM files

<? The 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" > The < 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.com piler. Source > 1.8 < / maven.com piler source > </properties> <dependencies> <dependency> <groupId> </groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> < groupId > javax.mail. Servlet < / groupId > < artifactId > javax.mail. The 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> < the 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 > The < configuration > < source > 1.8 < / source > < target > 1.8 < / target > < encoding > utf-8 < / encoding > <compilerArgs>-parameters</compilerArgs> </configuration> </plugin> </plugins> </build> </project>Copy the code

Test access specifichttp://localhost:8080/demo/query?name=zhaozhenThere is no problemCode address isGithub.com/zhendiao/de…

Welcome to search attention to my public number [micro view technology], and summary of classified interview questions github.com/zhendiao/Ja…