自定义简陋版SpringMVC

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 这几天在家写了一个简陋版的SpringMVC,先把代码贴出来,有兴趣的同学可以看一下。首先定义了一个简陋的服务器,其实也就是用了ServerSocket写了一个服务端(更详细的点看这里:创建一个简单的web服务器):public class ...

这几天在家写了一个简陋版的SpringMVC,先把代码贴出来,有兴趣的同学可以看一下。

首先定义了一个简陋的服务器,其实也就是用了ServerSocket写了一个服务端(更详细的点看这里:创建一个简单的web服务器):

public class HttpServer {

    public static void main(String[] args) {

        await();
    }

    private static void await() {

        ServerSocket serverSocket = null;
        try {
            ApplicationContext ac = new ApplicationContext(new HttpServletImpl(), "/com/zkn/fullstacktraining/spring/one/spring-config.properties");
            ac.init();
            boolean shutDown = false;
            //创建一个服务端
            serverSocket = new ServerSocket(8005, 1, InetAddress.getByName("127.0.0.1"));
            //用线程池处理请求
            ExecutorService executorService = new ThreadPoolExecutor(10,
                    10, 0L, TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(),
                    new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build());
            while (!shutDown) {
                //接收客户端请求
                ProcessSocket processSocket = new ProcessSocket(serverSocket.accept());
                executorService.execute(processSocket);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }
}
这里用了线程池来处理多个socket连接。
接着我们需要自定义一个Request和Response两个类来处理请求和响应信息。

Request这里存了请求头信息、请求参数信息、请求类型、请求URI等。Request的代码如下:

public class Request {
    /**
     * 输入流
     */
    private InputStream inputStream;
    /**
     * 头文件信息
     */
    private Map<String, String> headerMap = new HashMap<>();
    /**
     * 参数信息
     */
    private Map<String, Object> parameterMap = new HashMap<>();
    /**
     * 是否被解析过
     */
    private boolean isParser = false;
    /**
     * 请求类型
     */
    private String requestMethod;
    /**
     * 请求URI
     */
    private String uri;

    public Request(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    /**
     * 获取头文件信息
     *
     * @param key
     * @return
     */
    public String getHeader(String key) {
        if (key == null) {
            return null;
        }
        return headerMap.get(key.toLowerCase());
    }

    /**
     * 获取参数的值
     *
     * @param key
     * @return
     */
    public String getParameterValue(String key) {
        Object obj = parameterMap.get(key);
        if (obj == null)
            return null;
        if (obj instanceof List) {
            if (!((List) obj).isEmpty()) {
                return (String) ((List) obj).get(0);
            }
            return null;
        }
        return (String) obj;
    }

    /**
     * 获取多个值
     *
     * @param key
     * @return
     */
    public List<String> getParameterValues(String key) {
        Object obj = parameterMap.get(key);
        if (obj == null) {
            return null;
        }
        if (obj instanceof List) {
            return (List<String>) obj;
        }
        return null;
    }

    /**
     * 获取所有的key
     *
     * @return
     */
    public Set<String> getParameterNames() {

        return parameterMap.keySet();
    }

    public String getRequestMethod() {

        return requestMethod;
    }

    /**
     * 解析请求
     */
    public void parseRequest() {

        if (isParser) {
            return;
        }
        isParser = true;
        //这里用了BufferedReader 没有考虑性能问题
        BufferedReader lineNumberReader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            //获取请求行 请求行格式 Method URI 协议
            String str = lineNumberReader.readLine();
            if (str != null) {
                String[] strArray = str.split(" ");
                requestMethod = strArray[0];
                parseUrl(strArray[1]);
            }
            String headerStr = null;
            String[] strArr = null;
            //解析头信息
            while ((headerStr = lineNumberReader.readLine()) != null) {
                if ("".equals(headerStr)) {
                    break;
                }
                strArr = headerStr.split(":");
                if (strArr.length == 2) {
                    headerMap.put(strArr[0].toLowerCase(), strArr[1].trim());
                }
            }
            //如果是POST请求
            String contentType = null;
            if ("POST".equals(requestMethod)) {
                //文件上传
                if ((contentType = headerMap.get("content-type")) != null && headerMap.get("content-type").startsWith("multipart/form-data")) {
                    //解析文件上传
                    parseUploadFile(lineNumberReader, contentType);
                } else {
                    //非文件上传
                    String postParameter = "";
                    while ((postParameter = lineNumberReader.readLine()) != null) {
                        if ("".equals(postParameter)) {
                            break;
                        }
                        wrapperParameterValue(postParameter);
                    }
                }
            }
            System.out.println(JSON.toJSONString(parameterMap));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("执行完了。。。");
    }

    private void parseUploadFile(BufferedReader lineNumberReader, String contentType) throws IOException {
        String str;//文件上传的分割位 这里只处理单个文件的上传
        String boundary = contentType.substring(contentType.indexOf("boundary") + "boundary=".length());
        //解析消息体
        while ((str = lineNumberReader.readLine()) != null) {
            //解析结束的标记
            do {
                //读取boundary中的内容
                //读取Content-Disposition
                str = lineNumberReader.readLine();
                //说明是文件上传
                if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {
                    str = str.substring("Content-Disposition:".length());
                    String[] strs = str.split(";");
                    String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];
                    System.out.println("fileName = " + fileName);
                    //这一行是Content-Type
                    lineNumberReader.readLine();
                    //这一行是换行
                    lineNumberReader.readLine();
                    //正式去读文件的内容
                    BufferedWriter bw = null;
                    try {
                        bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("G:\\LearnVideo\\fileLoad" + File.separator + fileName), "UTF-8"));
                        while (true) {
                            str = lineNumberReader.readLine();
                            if (str.startsWith("--" + boundary)) {
                                break;
                            }
                            bw.write(str);
                            bw.newLine();
                        }
                        bw.flush();
                    } catch (Exception e) {

                    } finally {
                        if (bw != null) {
                            bw.close();
                        }
                    }
                }
                if (str.indexOf("Content-Disposition:") >= 0) {
                    str = str.substring("Content-Disposition:".length());
                    String[] strs = str.split(";");
                    String name = strs[strs.length - 1].replace("\"", "").split("=")[1];
                    lineNumberReader.readLine();
                    StringBuilder stringBuilder = new StringBuilder();
                    while (true) {
                        str = lineNumberReader.readLine();
                        if (str.startsWith("--" + boundary)) {
                            break;
                        }
                        stringBuilder.append(str);
                    }
                    parameterMap.put(name, stringBuilder.toString());
                }
            } while (("--" + boundary).equals(str));
            //解析结束
            if (str.equals("--" + boundary + "--")) {
                break;
            }
        }
    }

    /**
     * 解析URI
     *
     * @param s
     */
    private void parseUrl(String s) {
        if ("/".equals(s)) {
            uri = "/";
            return;
        }
        String tempStr = s;
        /**
         * 说明可能带参数
         */
        int flag = 0;
        if ((flag = tempStr.indexOf("?")) > 0) {
            uri = tempStr.substring(0, flag);
            if (tempStr.length() > (flag + 1)) {
                tempStr = tempStr.substring(flag + 1, tempStr.length());
                String[] strArray = tempStr.split("&");
                for (String str : strArray) {
                    wrapperParameterValue(str);
                }
            }
            return;
        }
        uri = s;
    }

    /**
     * 组装参数值
     *
     * @param str
     */
    private void wrapperParameterValue(String str) {
        Object value;
        String[] strArr = str.split("=");
        if (strArr.length == 2) {
            value = parameterMap.get(strArr[0]);
            if (value == null) {
                parameterMap.put(strArr[0], strArr[1]);
            } else {
                if (value instanceof List) {
                    ((List) value).add(strArr[1]);
                } else {
                    List<String> list = new ArrayList<>(2);
                    list.add((String) value);
                    list.add(strArr[1]);
                    parameterMap.put(strArr[0], strArr[1]);
                }
            }
        }
    }

    public String getUri() {
        return uri;
    }
Response这里只处理了返回简单字符串和返回静态资源文件,Response的代码如下:

public class Response {
    /**
     * 输出流
     */
    private OutputStream outputStream;
    /**
     * 字符输出流
     */
    private PrintWriter printWriter;
    /**
     * 请求类
     */
    private Request request;
    /**
     * Cookie信息
     */
    private List<Cookie> cookieList = new ArrayList<>(2);

    public Response(OutputStream outputStream, Request request) {
        this.outputStream = outputStream;
        this.request = request;
    }

    public void sendStaticResource(String path) {
        FileInputStream fis = null;
        try {
            if ("/".equals(path)) {
                path = "/static/html/index.html";
            } else {
                path = request.getUri();
            }
            URL url = this.getClass().getResource(path);
            if (url != null) {
                File file = new File(url.getFile());
                if (file.exists() && !file.isDirectory() && file.canRead()) {
                    fis = new FileInputStream(file);
                    int flag = 0;
                    byte[] bytes = new byte[1024];
                    while ((flag = fis.read(bytes)) != -1) {
                        outputStream.write(bytes, 0, flag);
                    }
                }
            } else {
                PrintWriter printWriter = getWriter();
                //这里用PrintWriter字符输出流,设置自动刷新
                printWriter.write("HTTP/1.1 404 File Not Found \r\n");
                printWriter.write("Content-Type: text/html\r\n");
                printWriter.write("Content-Length: 23\r\n");
                printWriter.write("\r\n");
                printWriter.write("<h1>File Not Found</h1>");
                printWriter.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public PrintWriter getWriter() throws IOException {
        printWriter = new PrintWriter(outputStream, true);
        return printWriter;
    }

    public void sendSuccess() {
        PrintWriter printWriter = null;
        try {
            printWriter = getWriter();
            //这里用PrintWriter字符输出流,设置自动刷新
            printWriter.write("HTTP/1.1 200 OK \r\n");
            printWriter.write("Content-Type: text/html;charset=utf-8\r\n");
            printWriter.write("Content-Length: " + "成功了".getBytes().length + "\r\n");
            if (cookieList != null && !cookieList.isEmpty()) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < cookieList.size(); i++) {
                    //设置多个Cookie
                    sb.append("Set-Cookie: ").append(cookieList.get(i).getKey()).append("=").append(cookieList.get(i).getValue()).append("\r\n");
                }
                printWriter.write(sb.toString());
            }
            printWriter.write("\r\n");
            printWriter.write("成功了");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            printWriter.close();
        }
    }

    public void addCookie(Cookie cookie) {
        cookieList.add(cookie);
    }
}
这里我们模仿Servlet,也自定义一个Servlet接口。代码如下:

public interface Servlet {

    void init();

    void service(Request request, Response response) throws  Exception;

    void destory();
}
它的一个实现类如下,在这个类中我们根据URI找到对应的请求处理类,并调用响应的请求方法。

public class HttpServletImpl implements Servlet {

    private StaticResourceProcessor resouce = new StaticResourceProcessor();

    @Override
    public void init() {
        System.out.println("我被初始化了、、、、、");
    }

    @Override
    public void service(Request request, Response response) throws Exception {
        String uri = request.getUri();
        if ("/".equals(uri) || (!StringUtils.isEmpty(uri) && uri.startsWith("/static/"))) {
            //处理静态资源
            resouce.process(request, response);
        } else {
            RequestMappingInfo mappingInfo = ApplicationContext.mappingMap.get(uri);
            if (mappingInfo != null) {
                List<String> parameterList = mappingInfo.getParameter();
                int parLen = mappingInfo.getParameter().size() - 1;
                Class<?>[] clazzs = mappingInfo.getFormalParameter();
                List<Object> list = new ArrayList<>();
                Object obj = null;
                if (clazzs != null) {
                    for (int i = 0; i < clazzs.length; i++) {
                        obj = getObject(request, response, parameterList, parLen < i, clazzs[i], i);
                        list.add(obj);
                    }
                }
                mappingInfo.getMethod().invoke(mappingInfo.getObj(), list.toArray());
                response.sendSuccess();
            }
        }
    }

    /**
     * 组装方法的参数
     *
     * @param request
     * @param response
     * @param parameterList
     * @param b
     * @param clazz
     * @param i
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private Object getObject(Request request, Response response, List<String> parameterList, boolean b, Class<?> clazz, int i) throws InstantiationException, IllegalAccessException {
        Object obj = null;
        //如果参数类型为Request
        if (clazz.isAssignableFrom(Request.class)) {
            obj = request;
        } else if (clazz.isAssignableFrom(Response.class)) {
            //如果参数类型为Response
            obj = response;
        }
        //如果是字节类型(包含基本类型和包装类)
        else if (clazz == byte.class || clazz == Byte.class) {
            if (!b) {
                obj = Byte.parseByte(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是short类型(包含基本类型和包装类)
        else if (clazz == short.class || clazz == Short.class) {
            if (!b) {
                obj = Short.parseShort(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是char类型(包含基本类型和包装类)
        else if (clazz == char.class || clazz == Character.class) {

        }
        //如果是整型(包含基本类型和包装类)
        else if (clazz == int.class || clazz == Integer.class) {
            if (!b) {
                obj = Integer.parseInt(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是float(包含基本类型和包装类)
        else if (clazz == float.class || clazz == Float.class) {
            if (!b) {
                obj = Float.parseFloat(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是double(包含基本类型和包装类)
        else if (clazz == double.class || clazz == Double.class) {
            if (!b) {
                obj = Double.parseDouble(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是double(包含基本类型和包装类)
        else if (clazz == long.class || clazz == Long.class) {
            if (!b) {
                obj = Long.parseLong(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是boolean(包含基本类型和包装类)
        else if (clazz == boolean.class || clazz == Boolean.class) {
            if (!b) {
                obj = Boolean.parseBoolean(request.getParameterValue(parameterList.get(i)));
            }
        }
        //如果是boolean(包含基本类型和包装类)
        else if (clazz == String.class) {
            if (!b) {
                obj = request.getParameterValue(parameterList.get(i));
            }
        }
        //如果是日期类型,先不做处理
        else if (clazz == Date.class) {
            obj = new Date();
        } else {
            //暂不考虑数组、集合、Map等类型
            obj = clazz.newInstance();
            Field[] fields = obj.getClass().getDeclaredFields();
            wrapperObjectFieldValue(request, obj, fields);
        }
        return obj;
    }

    /**
     * 组装属性对象值
     *
     * @param request
     * @param obj
     * @param fields
     * @throws IllegalAccessException
     */
    private void wrapperObjectFieldValue(Request request, Object obj, Field[] fields) throws IllegalAccessException {
        if (fields != null) {
            Field field = null;
            for (int j = 0; j < fields.length; j++) {
                field = fields[j];
                String fieldName = field.getName();
                field.setAccessible(true);
                String value = request.getParameterValue(fieldName);
                if (value != null && !"".equals(value)) {
                    if (field.getType() == byte.class || field.getType() == Byte.class) {
                        field.set(obj, Byte.parseByte(value));
                    }
                    //如果是short类型(包含基本类型和包装类)
                    else if (field.getType() == short.class || field.getType() == Short.class) {
                        field.set(obj, Short.parseShort(value));
                    }
                    //如果是char类型(包含基本类型和包装类)
                    else if (field.getType() == char.class || field.getType() == Character.class) {
                        field.set(obj, value.toCharArray()[0]);
                    }
                    //如果是整型(包含基本类型和包装类)
                    else if (field.getType() == int.class || field.getType() == Integer.class) {
                        field.set(obj, Integer.parseInt((value)));
                    }
                    //如果是float(包含基本类型和包装类)
                    else if (field.getType() == float.class || field.getType() == Float.class) {
                        field.set(obj, Float.parseFloat((value)));
                    }
                    //如果是double(包含基本类型和包装类)
                    else if (field.getType() == double.class || field.getType() == Double.class) {
                        field.set(obj, Double.parseDouble((value)));
                    }
                    //如果是double(包含基本类型和包装类)
                    else if (field.getType() == long.class || field.getType() == Long.class) {
                        field.set(obj, Long.parseLong((value)));
                    }
                    //如果是boolean(包含基本类型和包装类)
                    else if (field.getType() == boolean.class || field.getType() == Boolean.class) {
                        field.set(obj, Boolean.parseBoolean((value)));
                    }
                    //如果是boolean(包含基本类型和包装类)
                    else if (field.getType() == String.class) {
                        field.set(obj, value);
                    }
                }
            }
        }
    }

    @Override
    public void destory() {

    }
}
接着我们模仿Spring写几个注解:

模仿Spring的Autowire注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CustomAutowire {

    String name() default "";

}
模仿Spring的Component注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomComponent {

}
模仿Controller注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomController {

}
模仿RequestMapping注解:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface CustomRequestMapping {

    /**
     * URI
     * @return
     */
    String value();
    /**
     * 参数信息
     * @return
     */
    String[] parameter() default "";
}
这里根据请求找到对应的处理类和处理方法的思路是:定义一个Map,key是请求URI,value是自定义的一个类。这个自定义的类(RequestMappingInfo)包含这几个信息:Class信息、Method类、对象、请求参数和方法参数 java类在编译为class的时候有release和debug模式之分,在命令行中直接使用javac进行编译的时候,默认的时候release模式,使用release模式会改变形参中的参数名。而IDE都是使用debug模式进行编译的。ant编译的时候,需要在ant的配置文件中指定debug="true"。 如果要修改javac编译类文件的方式的话,需要指定-g参数。即:javac -g 类文件。通常我们都是用IDE进行项目开发的,所以我们的java类在编译成class的时候参数是不会变的 ,而SpringMVC在处理参数这个地方用到了ASM技术,来获取参数的信息,并且是在第一次处理请求的时候,来获取参数信息并放到缓存中,以后都从缓存中获取参数信息。RequestMappingInfo代码如下:

public class RequestMappingInfo {
    /**
     * 类名
     */
    private Class<?> clazz;
    /**
     * 方法名
     */
    private Method method;
    /**
     * 对象
     */
    private Object obj;
    /**
     * 参数
     */
    private List<String> parameter;
    /**
     * 方法的参数
     */
    private Class<?>[] formalParameter;
	//省略get set方法
}
接着我们定义一个类方便IOC:

public class BeanDefinitionInfo implements Serializable {

    private static final long serialVersionUID = -5988012842492544219L;
    /**
     * 类信息
     */
    private Class<?> clazz;
    /**
     * 对象
     */
    private Object object;
    /**
     * 父类
     */
    private List<Class<?>> superClass;
	//省略 get set
}
接着就是我们比较重要的类了ApplicationContext,我们会在这里类中,简单模仿Spring IOC的过程,扫描固定包下固定注解的类。在这里遇到了一个问题,一开始在加载类的时候自己写了一个类加载器,但是一个类加载器在他的生命周期中只会加载这个类一次,所以会出现多次加载同一个类的情况。后来别人推荐了一个小工具类: Reflections,这个问题才比较完美的解决,Reflections是一个很不错的工具类,可以扫描Classpath下面任意的类,并且让反射更容易。如下:扫描带某个注解的类,获取含有方法名为某个字符串的类等等。github地址在这儿:https://github.com/ronmamo/reflections,里面有很多例子。自定义的ApplicationContext的代码如下:

public class ApplicationContext {

    public static final Map<String, RequestMappingInfo> mappingMap = new HashMap<>();
    /**
     * 所有扫描到的类
     */
    private static final Map<Class<?>, BeanDefinitionInfo> allScanClazz = new HashMap<>();
    private static final List<Class<?>> allClass = Lists.newArrayList();

    private static Servlet servlet;
    private CustomInputStreamSource streamSource = null;

    public ApplicationContext(Servlet servlet, String location) {
        this.servlet = servlet;
        streamSource = new CustomClasspathResource(location);
    }

    public void init() throws Exception {
        Properties properties = new Properties();
        properties.load(streamSource.getInputStream());
        String componentScan = properties.getProperty("component.scan");
        wrapperCompontent(componentScan);
        imitateIOC();
        servlet.init();
    }

    private void wrapperCompontent(String componentScan) throws InstantiationException, IllegalAccessException {
        Reflections reflection = new Reflections(componentScan);
        //扫描所有有CustomController注解的类
        Set<Class<?>> controllerClazz = reflection.getTypesAnnotatedWith(CustomController.class);
        //扫描所有有CustomComponent注解的类
        Set<Class<?>> componentClazz = reflection.getTypesAnnotatedWith(CustomComponent.class);
        //扫描所有有CustomService注解的类
        Set<Class<?>> serviceClazz = reflection.getTypesAnnotatedWith(CustomService.class);
        for (Iterator<Class<?>> it = controllerClazz.iterator(); it.hasNext(); ) {
            wrapperController(it.next());
        }
        componentClazz.addAll(serviceClazz);
        for (Iterator<Class<?>> it = componentClazz.iterator(); it.hasNext(); ) {
            Class<?> clazz = it.next();
            BeanDefinitionInfo beanDefinitionInfo = new BeanDefinitionInfo();
            beanDefinitionInfo.setClazz(clazz);
            wrapperSuperClass(clazz, beanDefinitionInfo);
            allScanClazz.put(clazz, beanDefinitionInfo);
            allClass.add(clazz);
        }
    }

    /**
     * 模仿IOC
     *
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void imitateIOC() throws InstantiationException, IllegalAccessException {
        Object instance = null;
        BeanDefinitionInfo beanDefinitionInfo = null;
        for (Map.Entry<Class<?>, BeanDefinitionInfo> entry : allScanClazz.entrySet()) {
            Class clazz = entry.getKey();
            beanDefinitionInfo = entry.getValue();
            instance = beanDefinitionInfo.getObject();
            if (instance == null) {
                instance = clazz.newInstance();
                beanDefinitionInfo.setObject(instance);
            }
            Field[] fields = clazz.getDeclaredFields();
            if (fields != null && fields.length > 0) {
                for (int i = 0; i < fields.length; i++) {
                    if (!fields[i].isAccessible()) {
                        fields[i].setAccessible(true);
                    }
                    if (AnnotationUtil.isAutowire(fields[i])) {
                        Class tmpClass = fields[i].getType();
                        if (tmpClass.isInterface()) {
                            BeanDefinitionInfo tmpBean = null;
                            for (int j = 0; j < allClass.size(); j++) {
                                tmpBean = allScanClazz.get(allClass.get(j));
                                if (tmpClass.isAssignableFrom(tmpBean.getClazz())) {
                                    if (tmpBean.getObject() == null) {
                                        Object tmp = tmpBean.getClazz().newInstance();
                                        tmpBean.setObject(tmp);
                                    }
                                    fields[i].set(instance, tmpBean.getObject());
                                    break;
                                }
                            }
                        } else {
                            BeanDefinitionInfo tmpBean = allScanClazz.get(tmpClass);
                            if (tmpBean.getObject() == null) {
                                tmpBean.setObject(tmpBean.getClazz().newInstance());
                            }
                            fields[i].set(instance, tmpBean.getObject());
                        }
                    }
                }
            }
        }
    }

    /**
     * 组装Controller
     *
     * @param clazz
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private void wrapperController(Class<?> clazz) throws IllegalAccessException, InstantiationException {
        Object obj = clazz.newInstance();
        BeanDefinitionInfo beanDefinitionInfo = new BeanDefinitionInfo();
        beanDefinitionInfo.setClazz(clazz);
        beanDefinitionInfo.setObject(obj);
        wrapperSuperClass(clazz, beanDefinitionInfo);
        allScanClazz.put(clazz, beanDefinitionInfo);
        String str = "";
        CustomRequestMapping customRequestMapping = null;
        if ((customRequestMapping = isRequestMapping(clazz)) != null) {
            if (customRequestMapping.value().startsWith("/")) {
                str = customRequestMapping.value();
            } else {
                str = "/" + customRequestMapping.value();
            }
        }
        Method[] methodArray = clazz.getMethods();
        if (methodArray != null) {
            RequestMappingInfo requestMappingInfo = null;
            for (Method method : methodArray) {
                customRequestMapping = method.getAnnotation(CustomRequestMapping.class);
                if (customRequestMapping != null) {
                    requestMappingInfo = new RequestMappingInfo();
                    requestMappingInfo.setClazz(clazz);
                    requestMappingInfo.setMethod(method);
                    requestMappingInfo.setObj(obj);
                    Class<?>[] clazzs = method.getParameterTypes();
                    String strInner = "";
                    if (clazzs != null) {
                        requestMappingInfo.setFormalParameter(clazzs);
                    }
                    if (customRequestMapping.value().startsWith("/")) {
                        strInner = customRequestMapping.value();
                    } else {
                        strInner = "/" + customRequestMapping.value();
                    }
                    String[] parameter = customRequestMapping.parameter();
                    if (parameter != null && parameter.length > 0) {
                        requestMappingInfo.setParameter(Arrays.asList(parameter));
                    }
                    mappingMap.put(str + strInner, requestMappingInfo);
                }
            }
        }
    }

    /**
     * 组装父类
     *
     * @param clazz
     * @param beanDefinitionInfo
     */
    private void wrapperSuperClass(Class<?> clazz, BeanDefinitionInfo beanDefinitionInfo) {
        Class<?> tmp = clazz;
        List<Class<?>> superList = Lists.newArrayList();
        while (tmp.getSuperclass() != null && tmp.getSuperclass() != Object.class) {
            superList.add(clazz.getSuperclass());
            tmp = clazz.getSuperclass();
        }
        beanDefinitionInfo.setSuperClass(superList);
    }

    public CustomRequestMapping isRequestMapping(Class<?> clazz) {
        return clazz.getAnnotation(CustomRequestMapping.class);
    }

    public static Servlet getServlet() {
        return servlet;
    }
下面我们写个Controller类来测试一下:

@CustomController
@CustomRequestMapping(value = "/custom")
public class FirstPageController {

    @CustomAutowire
    private UserService userService;

    @CustomRequestMapping(value = "/myFirstPage.do")
    public void myFirstPage() {
        System.out.println("我被调用了、、、、");
    }

    /**
     * 插入操作
     *
     * @param userScope
     */
    @CustomRequestMapping(value = "/inserUser.do")
    public void inserUser(UserScope userScope, Response response) {
        Cookie cookie = new Cookie("test", "testcookie");
        Cookie cookie2 = new Cookie("test02", "testcookie02");
        response.addCookie(cookie);
        response.addCookie(cookie2);
        System.out.println("我是插入操作的Controller层、、、、");
        userService.insert(userScope);
    }
}
我们在浏览器中输入:http://localhost:8005/custom/myFirstPage.do来看一下结果:

控制台输出如下:



返回结果如下:


和我们程序写的结果一样。

接着我们写一个稍微复杂一点的,定义一个javaBean、DAO类、Service类。
UserScope

public class UserScope implements Serializable{

    private static final long serialVersionUID = -8340887359752275426L;
    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String passWord;
	//省略get set
}
DAO

public interface UserDAO {
    /**
     * 插入用户信息
     * @param user
     * @return
     */
    Integer insert(UserScope user);
}
@CustomComponent
public class UserDAOImpl implements UserDAO {

    private Random random = new Random();

    @Override
    public Integer insert(UserScope user) {
        System.out.println("我是DAO层。。。。进行插入操作......");
        System.out.println(JSON.toJSONString(user));
        return random.nextInt();
    }
}
Service:

public interface UserService {
    /**
     * 插入用户信息
     * @param userScope
     * @return
     */
    Integer insert(UserScope userScope);
}
@CustomService
public class UserServiceImpl implements UserService {

    @CustomAutowire
    private UserDAO userDAO;

    /**
     * 插入用户信息
     *
     * @param userScope
     * @return
     */
    @Override
    public Integer insert(UserScope userScope) {
        System.out.println("我是Service层。。。。进行插入操作......");
        return userDAO.insert(userScope);
    }
}
从上面的代码中我们可以看到在DAO的实现类上我们用了CustomComponent注解,在Service的实现类上我们用了CustomService的注解。在我们的那个Controller中我们又用了CustomAutowire这个注解。下面我们访问一下看看效果,我们在浏览器中输入:http://localhost:8005/custom/inserUser.do?userName=hangssewe&passWord=2ewewe

控制台输出如下:


浏览器输出为:


我们在Controller中的inserUser这个方法中设置了两个Cookie,我们来看一下Cookie有没有设置成功:


结果和我们预想的是一样的。

接着我们写一个静态资源的处理类:

public class StaticResourceProcessor {

    public void process(Request request, Response response) {

        response.sendStaticResource(request.getUri());
    }
}
访问一下看看效果如何:



这里遇到的一个问题是在Chrome浏览器中访问的时候会报错,在IE浏览器中访问则正常显示,还没搞清楚为什么会出现这样的问题。

完整的代码请点击这里:https://github.com/zhangconan/fullstacktraining/tree/master/src/main/java/com/zkn/fullstacktraining/spring/one






相关文章
|
3月前
|
Java 网络架构
springboot配合thymeleaf,调用接口不跳转页面只显示文本
springboot配合thymeleaf,调用接口不跳转页面只显示文本
159 0
|
4月前
|
XML JSON Java
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
本文介绍了如何使用IntelliJ IDEA和Maven搭建一个整合了Struts2、Spring4、Hibernate4的J2EE项目,并配置了项目目录结构、web.xml、welcome.jsp以及多个JSP页面,用于刷新和学习传统的SSH框架。
128 0
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
|
6月前
|
Java 应用服务中间件 容器
手写SpringBoot(二)之动态切换Servlet容器
我们在切换serlvet容器的时候,会将SpringBoot默认的tomcat jar包给排除掉,换上我们需要的jar包,比如jetty。
54 0
|
7月前
|
JSON 前端开发 Java
SpringMVC03 基础操作续与几个简单的交互
SpringMVC03 基础操作续与几个简单的交互
39 0
|
7月前
|
Java
SpringBoot自定义错误页面与原理讲解
SpringBoot自定义错误页面与原理讲解
236 0
|
前端开发 Java
SpringMVC 各组件功能
SpringMVC 各组件功能
75 0
|
小程序 Java 程序员
SpringMVC bean加载控制 -- SpringMVC快速入门保姆级教程(二)
SpringMVC bean加载控制 -- SpringMVC快速入门保姆级教程(二)
|
监控 前端开发 Java
Spring相关概念注解及SpringMVC操作流程图集
Spring相关概念注解及SpringMVC操作流程图集
104 0
Spring相关概念注解及SpringMVC操作流程图集
|
Java API 前端开发
SpringBoot前后分离项目实现自定义登录拦截
版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82696896 ...
2153 0
|
数据挖掘 BI 调度
springMVC做Web开发已过时,现在都用 FineReport了
springMVC做Web开发已过时,现在都用 FineReport了
345 0
springMVC做Web开发已过时,现在都用 FineReport了