handlerAdapter与方法返回值的处理

前提:处理器方法被调用并返回了结果

public void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//调用处理器对应的处理器方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//设置响应状态,如果在调用处理器方法时发生了错误,用webRequest获取response对象并设置它的状态
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
//为TRUE标识请求已经结束
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }

@Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//遍历寻找能够处理中返回参数类型的处理器,如果没有找到就抛出异常,判断是否能够处理很简单就是调用处理器的support方法
        HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
//处理
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }

现在以RequestResponseBodyMethodProcessor为例

这个处理器是判断当前方法上面是否有@ResponseBody,如果有就表示这个方法能够支持处理。@Override
    public boolean supportsReturnType(MethodParameter returnType) {
//判断这个方法对应的类是否有@ResponseBody注解
        return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
//判断这个方法上是否有@ResponseBody注解
                returnType.getMethodAnnotation(ResponseBody.class) != null);
    }

@Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//设置requestHandled已经被处理
        mavContainer.setRequestHandled(true);

        // Try even with null return value. ResponseBodyAdvice could get involved.
        writeWithMessageConverters(returnValue, returnType, webRequest);
    }

protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//包装request和response对象
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }

protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//获取返回值的类型
        Class<?> returnValueClass = getReturnValueType(returnValue, returnType);
//获取返回值的泛型类型,比如List<String>,那么泛型类型就String.class
        Type returnValueType = getGenericType(returnType);
        HttpServletRequest servletRequest = inputMessage.getServletRequest();
//获取浏览器能够接受的类型
        List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
//获取返回的类型
        List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass, returnValueType);

        if (returnValue != null && producibleMediaTypes.isEmpty()) {
            throw new IllegalArgumentException("No converter found for return value of type: " + returnValueClass);
        }

        Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
        for (MediaType requestedType : requestedMediaTypes) {
            for (MediaType producibleType : producibleMediaTypes) {
//寻找兼容的媒体类型
                if (requestedType.isCompatibleWith(producibleType)) {
//保存两者中认为最好的类型作为兼容类型
                    compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
                }
            }
        }
//如果兼容类型为空,并且方法返回值又不为空,那么抛出异常,找不到浏览器能够接受的返回类型
        if (compatibleMediaTypes.isEmpty()) {
            if (returnValue != null) {
                throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
            }
            return;
        }

        List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
//对类型进行排序
        MediaType.sortBySpecificityAndQuality(mediaTypes);

        MediaType selectedMediaType = null;
        for (MediaType mediaType : mediaTypes) {
            if (mediaType.isConcrete()) {
//如果找到不是通配符的媒体类型就作为选择的媒体类型(就是非综合类型,那种不能表示到具体是哪一种类型的,比如MediaType.ALL)
                selectedMediaType = mediaType;
                break;
            }
//如果媒体类型是all(就是所有类型)或者是application应用类类型,那么设置成流类型
            else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
                selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                break;
            }
        }

        if (selectedMediaType != null) {
//去除权衡值,比如application/json;q=0.8,去除后变成application/json
            selectedMediaType = selectedMediaType.removeQualityValue();
//遍历所有注册的消息转换器,这里和解析参数时是差不多的操作
            for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
                if (messageConverter instanceof GenericHttpMessageConverter) {
                    if (((GenericHttpMessageConverter<T>) messageConverter).canWrite(returnValueType,
                            returnValueClass, selectedMediaType)) {
//调用实现了ResponseBodyAdvice的controller,对值进行处理
                        returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
                                (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                                inputMessage, outputMessage);
                        if (returnValue != null) {
                            addContentDispositionHeader(inputMessage, outputMessage);
                            ((GenericHttpMessageConverter<T>) messageConverter).write(returnValue,
                                    returnValueType, selectedMediaType, outputMessage);
                            if (logger.isDebugEnabled()) {
                                logger.debug("Written [" + returnValue + "] as \"" +
                                        selectedMediaType + "\" using [" + messageConverter + "]");
                            }
                        }
                        return;
                    }
                }
                else if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
                    returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
                            (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                            inputMessage, outputMessage);
                    if (returnValue != null) {
                        addContentDispositionHeader(inputMessage, outputMessage);
                        ((HttpMessageConverter<T>) messageConverter).write(returnValue,
                                selectedMediaType, outputMessage);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Written [" + returnValue + "] as \"" +
                                    selectedMediaType + "\" using [" + messageConverter + "]");
                        }
                    }
                    return;
                }
            }
        }

        if (returnValue != null) {
            throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
        }
    }

//遍历实现了ResponseBodyAdvice的Controller
private <T> Object processBody(Object body, MethodParameter returnType, MediaType contentType,
            Class<? extends HttpMessageConverter<?>> converterType,
            ServerHttpRequest request, ServerHttpResponse response) {

        for (ResponseBodyAdvice<?> advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) {
//判断是否支持,最后使用outputmessage写出到客户端
            if (advice.supports(returnType, converterType)) {
                body = ((ResponseBodyAdvice<T>) advice).beforeBodyWrite((T) body, returnType,
                        contentType, converterType, request, response);
            }
        }
        return body;
    }

处理完后返回。

再来看看ModelAndViewMethodReturnValueHandler是这么处理返回值的

@Override
    public boolean supportsReturnType(MethodParameter returnType) {
//处理返回类型是ModelAndView的方法
        return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
    }

@Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//如果返回值为空,那么设置请求结束
        if (returnValue == null) {
            mavContainer.setRequestHandled(true);
            return;
        }

        ModelAndView mav = (ModelAndView) returnValue;
//判断视图名是否为String类型
        if (mav.isReference()) {
//获取视图名称
            String viewName = mav.getViewName();
//给视图容器设置视图名称
            mavContainer.setViewName(viewName);
//如果是重定向视图名称,那么设置重定向表示为true,如果没有重新配置这个handler,并且设置自定的标识符,默认就是判断这个视图名是否以redirect:开头
            if (viewName != null && isRedirectViewName(viewName)) {
                mavContainer.setRedirectModelScenario(true);
            }
        }
        else {
//如果视图不是String类型的,那么就是视图对象
            View view = mav.getView();
            mavContainer.setView(view);
//判断是否是smartView,如果是,再判断是否是重定向视图,如果是就设置重定向标识
            if (view instanceof SmartView) {
                if (((SmartView) view).isRedirectView()) {
                    mavContainer.setRedirectModelScenario(true);
                }
            }
        }
//将ModelAndView中的属性全部存到ModelAndViewContainer中
        mavContainer.addAllAttributes(mav.getModel());
    }

接着调用了以下方法

getModelAndView(mavContainer, modelFactory, webRequest);

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
            ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//更新Model
        modelFactory.updateModel(webRequest, mavContainer);
//如果是json处理方式的,那么这个request已经处理完了,返回null,如果是其他的,需要视图解析的,那么继续。
        if (mavContainer.isRequestHandled()) {
            return null;
        }
//获取model,会根据标识来判断是返回默认model还是重定向model
        ModelMap model = mavContainer.getModel();
        ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
        if (!mavContainer.isViewReference()) {
            mav.setView((View) mavContainer.getView());
        }
        if (model instanceof RedirectAttributes) {
            Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
        return mav;
    }

一下是获取model的方法
public ModelMap getModel() {
        if (useDefaultModel()) {
            return this.defaultModel;
        }
        else {
            if (this.redirectModel == null) {
                this.redirectModel = new ModelMap();
            }
            return this.redirectModel;
        }
    }

    /**
     * Whether to use the default model or the redirect model.
     */
    private boolean useDefaultModel() {
        return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
    }

更新Model
public void updateModel(NativeWebRequest request, ModelAndViewContainer container) throws Exception {
//获取默认的Model,sessionAttribute注释的属性,只有model和modelMap才能用,redirectModel没有用。
        ModelMap defaultModel = container.getDefaultModel();
//检查是否已经被清理了,在handlerMethod中可以调用SessionStatus的setComplete方法用于标识要清理数据
        if (container.getSessionStatus().isComplete()){
            this.sessionAttributesHandler.cleanupAttributes(request);
        }
        else {
//如果没有被清理就将注解中定义要保存的key存到session中
//储存sessionAttribute,这个功能可以用来做缓存
            this.sessionAttributesHandler.storeAttributes(request, defaultModel);
        }
//如果请求没有结束,并且获取的model是默认的model,那么就更新绑定结果
        if (!container.isRequestHandled() && container.getModel() == defaultModel) {
            updateBindingResult(request, defaultModel);
        }
    }

public void storeAttributes(WebRequest request, Map<String, ?> attributes) {
        for (String name : attributes.keySet()) {
            Object value = attributes.get(name);
            Class<?> attrType = (value != null) ? value.getClass() : null;
//判断是否是@SessionAttribute定义的属性名和类型,如果是就存到session中
            if (isHandlerSessionAttribute(name, attrType)) {
                this.sessionAttributeStore.storeAttribute(request, name, value);
            }
        }
    }

public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
        Assert.notNull(request, "WebRequest must not be null");
        Assert.notNull(attributeName, "Attribute name must not be null");
        Assert.notNull(attributeValue, "Attribute value must not be null");
        String storeAttributeName = getAttributeNameInSession(request, attributeName);
        request.setAttribute(storeAttributeName, attributeValue, WebRequest.SCOPE_SESSION);
    }

//更新绑定结果
private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
        List<String> keyNames = new ArrayList<String>(model.keySet());
        for (String name : keyNames) {
            Object value = model.get(name);
//将绑定结果,比如校验的结果,用于页面展示
            if (isBindingCandidate(name, value)) {
                String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;

                if (!model.containsAttribute(bindingResultKey)) {
                    WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
                    model.put(bindingResultKey, dataBinder.getBindingResult());
                }
            }
        }
    }

回到DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
//调用拦截器的preHandler方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
//如果没有设置视图,那么使用viewNameTranslator获取默认的视图名
                applyDefaultViewName(processedRequest, mv);
//调用拦截器的postHandle方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
//处理结果
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
//如果出现异常就触发拦截器的afterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
//如果出现异常就触发拦截器的afterCompletion方法
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

        boolean errorView = false;

        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
//获取handler
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);                //调用异常处理器处理数据。
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

        // Did the handler return a view to render?
        if (mv != null && !mv.wasCleared()) {
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Null ModelAndView returned to DispatcherServlet with name ‘" + getServletName() +
                        "‘: assuming HandlerAdapter completed request handling");
            }
        }

        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }

        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

//渲染方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Determine locale for request and apply it to the response.
//从request中获取本地信息
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);

        View view;
//判断mv中设置的视图是视图名称还是视图对象
        if (mv.isReference()) {
            // We need to resolve the view name.如果是视图名称,那么通过视图解析器解析获取视图对象{(protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
            HttpServletRequest request) throws Exception {

        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
        return null;
    }))
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name ‘" + mv.getViewName() +
                        "‘ in servlet with name ‘" + getServletName() + "‘");
            }
        }
        else {
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name ‘" + getServletName() + "‘");
            }
        }

        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name ‘" + getServletName() + "‘");
        }
        try {
//调用视图的渲染方法mv.getModelInternal()获取modelMap,我们的设置的参数在里面
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name ‘" +
                        getServletName() + "‘", ex);
            }
            throw ex;
        }
    }

InternalResourceViewResolver解析器(jstl)

protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
        view.setUrl(getPrefix() + viewName + getSuffix());

        String contentType = getContentType();
        if (contentType != null) {
            view.setContentType(contentType);
        }

        view.setRequestContextAttribute(getRequestContextAttribute());
        view.setAttributesMap(getAttributesMap());

        Boolean exposePathVariables = getExposePathVariables();
        if (exposePathVariables != null) {
            view.setExposePathVariables(exposePathVariables);
        }
        Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
        if (exposeContextBeansAsAttributes != null) {
            view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
        }
        String[] exposedContextBeanNames = getExposedContextBeanNames();
        if (exposedContextBeanNames != null) {
            view.setExposedContextBeanNames(exposedContextBeanNames);
        }

        return view;
    }

//合并属性
protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,
            HttpServletResponse response) {

        @SuppressWarnings("unchecked")
//判断是否要暴露路径变量供视图使用
        Map<String, Object> pathVars = (this.exposePathVariables ?
                (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);

        // Consolidate static and dynamic model attributes.
        int size = this.staticAttributes.size();
        size += (model != null ? model.size() : 0);
        size += (pathVars != null ? pathVars.size() : 0);

        Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);
        mergedModel.putAll(this.staticAttributes);
//将暴露的属性合并到modelMap中
        if (pathVars != null) {
            mergedModel.putAll(pathVars);
        }
        if (model != null) {
            mergedModel.putAll(model);
        }

        // Expose RequestContext?
        if (this.requestContextAttribute != null) {
            mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
        }
//将合并的数据返回
        return mergedModel;
    }

//渲染合并的model
protected void renderMergedOutputModel(
            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        // Expose the model object as request attributes.就是将属性设置到request,如果属性对应的值为空,那么就从request中移除
        exposeModelAsRequestAttributes(model, request);

        // Expose helpers as request attributes, if any.
        exposeHelpers(request);
//如果路径和当前请求的路径一样,那么就抛出错误
        // Determine the path for the request dispatcher.
        String dispatcherPath = prepareForRendering(request, response);
//获取请求分发器,request.getDispatcher(diapatcherPath)
        // Obtain a RequestDispatcher for the target resource (typically a JSP).
        RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
        if (rd == null) {
            throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
                    "]: Check that the corresponding file exists within your web application archive!");
        }

        // If already included or response already committed, perform include, else forward.
        if (useInclude(request, response)) {
            response.setContentType(getContentType());
            if (logger.isDebugEnabled()) {
                logger.debug("Including resource [" + getUrl() + "] in InternalResourceView ‘" + getBeanName() + "‘");
            }
            rd.include(request, response);
        }

        else {
            // Note: The forwarded resource is supposed to determine the content type itself.
            if (logger.isDebugEnabled()) {
                logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView ‘" + getBeanName() + "‘");
            }
请求转发
            rd.forward(request, response);
        }
    }

原文地址:https://www.cnblogs.com/honger/p/9516930.html

时间: 2024-10-15 20:14:46

handlerAdapter与方法返回值的处理的相关文章

struts2在配置文件中调用Action的方法返回值

struts2在配置文件中可以调用Action的方法返回值 1.Action中 //文件下载名 public String getDownloadFileName(){ String downloadFileName = ""; String filename = fileName + ".xls"; try { downloadFileName = URLEncoder.encode(filename,"UTF-8"); } catch (Un

使用Result代替ResultSet作为方法返回值

在开发过程中,我们不能将ResultSet对象作为方法的返回值,因为Connection连接一旦关闭,在此连接上的会话和在会话上的结果集也将会自动关闭,而Result对象则不会发生这种现象,所以在查询时尽量以Result对象作为方法返回值. import javax.servlet.jsp.jstl.sql.Result; import javax.servlet.jsp.jstl.sql.ResultSupport; ResultSet rs = executeQuery(sql, param

Spring MVC学习之三:处理方法返回值的可选类型

转自:http://www.cnblogs.com/cuizhf/p/3810652.html ———————————————————————————————————————————————————————————— spring mvc处理方法支持如下的返回方式:ModelAndView, Model, ModelMap, Map,View, String, void.下面将对具体的一一进行说明: ModelAndView @RequestMapping("/show1") publ

方法返回值 前面的&lt;T&gt;是什么?

如: public <T> ValueOperations<String,T> setCacheObject(String key,T value){                return null;            } 这个的T的声明,跟类后面的<T>没有关系.方法前面的<T>可以理解为是:给这个方法指定泛型,可以是自己独有的某个类都可以执行这个方法. 下边是找到的一个非常好的帖子: import java.util.*; class Frui

黑马程序员——关于java字节流的read()方法返回值为int的思考(转载)

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! -------  之前一直不明白java字节流的read()方法返回值为什么为int,今天在网上找到了答案.以下为转载,原文地址:http://blog.sina.com.cn/s/blog_9e351f9b01015kgp.html 我们都知道java中io操作分为字节流和字符流,对于字节流,顾名思义是按字节的方式读取数据,所以我们常用字节流来读取二进制流(如图片,音乐 等文件).问题是为什么字节流中定义的

SpringMVC处理器方法返回值void ajax方式

1.引入jar包 2.编写方法 //处理器方法返回值void @RequestMapping("/first") public void doFirst(HttpServletResponse response) throws IOException { //要返回给浏览器的数据 List<String> list=new ArrayList<String>(); list.add("a"); list.add("b");

SpringMVC入门(二)—— 参数的传递、Controller方法返回值、json数据交互、异常处理、图片上传、拦截器

一.参数的传递 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Helvetica } 1.简单的参数传递 1 /* @RequestParam用法:入参名字与方法名参数名不一致时使用{ 2 * value:传入的参数名,required:是否必填,defaultValue:默认值 3 * } 4 */ 5 @RequestMapping("itemEdit") 6 public ModelAndView itemEdit(@R

js 获取getElementsTagName()方法返回值的内容

<div id="news-top" class="section"> <h3>Some title</h3> <div class="content"> <ul> <li><span>HTML</span><a href="">Some Link1</a></li> <li><

方法返回值及其参数设置

底层源码 doDispatch getHandler HandlerMapping类 方法返回值 ThreadController类 参数 FourthController类 原文地址:https://www.cnblogs.com/dabrk/p/11826693.html