SpringMvc渲染视图

这篇博文讨论的问题是从ModelAndView如何渲染到页面。

首先要知道每个请求处理完之后都会返回一个ModelAndView对象。

这里我分6种情况来分析,代表6种返回类型:

  1. ModelAndView
  2. Map,ModelMap
  3. Model
  4. View
  5. String
  6. Void

我先贴出我的测试的后台代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 配置扫描的包 --><context:component-scan base-package="com"></context:component-scan><!-- 配置视图解析器,将方法的返回值映射到一个实际的物理视图 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/pages/result/"></property><property name="suffix" value=".jsp"></property></bean><mvc:default-servlet-handler/><mvc:annotation-driven></mvc:annotation-driven></beans>
package com.mmc.modelandview;import java.util.Date;
import java.util.Map;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView;import com.mmc.common.CommonParam;@Controller
public class TestModelAndView {@RequestMapping("testModelAndView")public ModelAndView testModelAndView(){ModelAndView modelAndView=new ModelAndView(CommonParam.SUCCESS);modelAndView.addObject("time", new Date());return modelAndView;}@RequestMapping("testModel")public String testModel(Model model){model.addAttribute("time",new Date());return CommonParam.SUCCESS;}@RequestMapping("testMap")public String testMap(Map<String,Object> map){map.put("person", "lixiaolu");return  CommonParam.SUCCESS;}@RequestMapping("testView")public View testView(View view){view=new JasperReportsPdfView();return view;}@RequestMapping("testString")public String testString(){return CommonParam.SUCCESS;} @RequestMapping("testForward")public String testForward(){return "forward:/hello";}@RequestMapping("testVoid")public void testVoid(){System.out.println("执行testVoid方法");}}

 

第一种:返回值是ModelAndView类型:

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()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}} //检查view有没有设置,如果没有给他设置一个默认的applyDefaultViewName(request, mv);
         //传给我们的拦截器,也就是说在拦截器里我们可以操作视图的映射mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {dispatchException = ex;}
       //就是去处理映射了 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}
catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Error err) {triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}

这个方法进去之后,经过一些判断,会执行到一个render(mv, request, response);方法,这个方法就是渲染视图的方法。这个方法进去之后

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {        // Determine locale for request and apply it to the response.        Locale locale = this.localeResolver.resolveLocale(request);       
response.setLocale(locale);View view;
if (mv.isReference()) {// We need to resolve the view name.
       //返回一个View对象
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 {
        //渲染视图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;}}

 

@Overridepublic void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isTraceEnabled()) {logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +" and static attributes " + this.staticAttributes);}//将我ModelAndView中modelAndView.addObject("time", new Date());的值放入mergeModel中Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);//判断是否读取本地缓存prepareResponse(request, response);
      //进一步处理,下面贴出它的代码renderMergedOutputModel(mergedModel, request, response);}
@Overriprotected void renderMergedOutputModel(
            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine which request handle to expose to the RequestDispatcher.
     //确定哪些请求处理暴露给RequestDispatcher。
HttpServletRequest requestToExpose = getRequestToExpose(request);// Expose the model object as request attributes.
     //把model里面的值放入request中
exposeModelAsRequestAttributes(model, requestToExpose);// Expose helpers as request attributes, if any. exposeHelpers(requestToExpose);// Determine the path for the request dispatcher.
     //获取要返回的地址
String dispatcherPath = prepareForRendering(requestToExpose, response);// Obtain a RequestDispatcher for the target resource (typically a JSP).
     //确定一个请求处理器为这些参数资源
RequestDispatcher rd = getRequestDispatcher(requestToExpose, 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(requestToExpose, response)) {response.setContentType(getContentType());if (logger.isDebugEnabled()) {logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");}rd.include(requestToExpose, 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(requestToExpose, response);}}

当要转发的地址,和要携带的信息都放入到requestToExpose里之后,就调用rd.forward(requestToExpose, response);转发请求到页面。

第二种:返回类型是Map

InvocableHandlerMethod类中有下面的方法:

public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {//mavContainer对象初始化时,会初始化一个默认的BindingAwareModelMap属性。将默认的这个BindingAwareModelMap属性放入arg

Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Invoking ["); sb.append(this.getBeanType().getSimpleName()).append("."); sb.append(getMethod().getName()).append("] method with arguments "); sb.append(Arrays.asList(args)); logger.trace(sb.toString()); }
     //执行我的业务方法,把arg数组传入,把我里面的mavContainer默认的modelMap赋上值Object returnValue = invoke(args);if (logger.isTraceEnabled()) {logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");}return returnValue;}

 然后将model取出来,和我返回的String一起构建ModelAndView对象。

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {modelFactory.updateModel(webRequest, mavContainer);if (mavContainer.isRequestHandled()) {return null;}
     //取出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

需要分析的就是我们加入model中的参数是怎么加入到modelAndView对象的。

其实是和Map类型也是一样的,将

mavContainer对象初始化时,会初始化一个默认的BindingAwareModelMap属性。将默认的这个BindingAwareModelMap属性放入arg,然后把arg传入我们的业务方法,然后业务方法接收到这个参数,往这个参数放值。就像我的例子里那样
 public String testModel(Model model){model.addAttribute("time",new Date());return CommonParam.SUCCESS;}

放好之后,model就有值了,然后根据这个model和我返回的字符串一起构建ModelAndView对象。

第四种:返回类型是View

这种我还没搞懂怎么用

第五种:返回类型是String

这个类ServletInvocableHandlerMethod的方法里:

public final void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {//这里返回我的String类型的值 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {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;}}

然后到ViewNameMethodReturnValueHandler类的这个方法里:

@Overridepublic void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws Exception {if (returnValue == null) {return;}else if (returnValue instanceof String) {
       //把返回值赋给mavContainer的ViewNameString viewName
= (String) returnValue;mavContainer.setViewName(viewName);if (isRedirectViewName(viewName)) {mavContainer.setRedirectModelScenario(true);}}else {// should not happenthrow new UnsupportedOperationException("Unexpected return type: " +returnType.getParameterType().getName() + " in method: " + returnType.getMethod());}}

然后通过mavContainer对象来构造一个ModelAndView对象,然后渲染视图。

第五种特别篇:返回值中带有redirect的字符串

在ViewNameMethodReturnValueHandler类中的handleReturnValue方法中:

@Overridepublic void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws Exception {if (returnValue == null) {return;}else if (returnValue instanceof String) {
       //同样是把带有redirect的字符串赋给mavContainer对象。String viewName
= (String) returnValue;mavContainer.setViewName(viewName);if (isRedirectViewName(viewName)) {mavContainer.setRedirectModelScenario(true);}}else {// should not happenthrow new UnsupportedOperationException("Unexpected return type: " +returnType.getParameterType().getName() + " in method: " + returnType.getMethod());}}

然后在DispatcherServlet类中有这个方法:

protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,HttpServletRequest request) throws Exception {for (ViewResolver viewResolver : this.viewResolvers) {
       //获取view,View是一个接口,这里的view实际类型是RedirectView View view
= viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}}return null;}

然后根据View类型的不同,调用的也是不同的renderMergedOutputModel方法,这是RedirectView类的方法:

@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,HttpServletResponse response) throws IOException {String targetUrl = createTargetUrl(model, request);targetUrl = updateTargetUrl(targetUrl, model, request, response);FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);if (!CollectionUtils.isEmpty(flashMap)) {UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build();flashMap.setTargetRequestPath(uriComponents.getPath());flashMap.addTargetRequestParams(uriComponents.getQueryParams());FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);if (flashMapManager == null) {throw new IllegalStateException("FlashMapManager not found despite output FlashMap having been set");}flashMapManager.saveOutputFlashMap(flashMap, request, response);} sendRedirect(request, response, targetUrl, this.http10Compatible);}

然后就是response.sendRedirect(encodedRedirectURL);

第五种特别篇之带forward的字符串:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.Locale locale = this.localeResolver.resolveLocale(request);response.setLocale(locale);View view;if (mv.isReference()) {// We need to resolve the view name.
       //选择不同的类型的视图处理器构建视图对象
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 {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;}}

这个是DispatcherServlet中的resolveViewName方法。

然后是选择了AbstractCachingViewResolver这个视图处理器的resolveViewName方法,去创建视图。然后调用了他的子类UrlBasedViewResolver的创建视图方法:

@Overrideprotected View createView(String viewName, Locale locale) throws Exception {// If this resolver is not supposed to handle the given view,// return null to pass on to the next resolver in the chain.if (!canHandle(viewName, locale)) {return null;}// Check for special "redirect:" prefix.if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());return applyLifecycleMethods(viewName, view);}// Check for special "forward:" prefix.
     //获得一个forwardUrl
if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());return new InternalResourceView(forwardUrl);}// Else fall back to superclass implementation: calling loadView.return super.createView(viewName, locale);}

然后调用InternalResourceView类的renderMergedOutputModel方法:

@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine which request handle to expose to the RequestDispatcher.HttpServletRequest requestToExpose = getRequestToExpose(request);// Expose the model object as request attributes.
        exposeModelAsRequestAttributes(model, requestToExpose);// Expose helpers as request attributes, if any.
        exposeHelpers(requestToExpose);// Determine the path for the request dispatcher.String dispatcherPath = prepareForRendering(requestToExpose, response);// Obtain a RequestDispatcher for the target resource (typically a JSP).RequestDispatcher rd = getRequestDispatcher(requestToExpose, 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(requestToExpose, response)) {response.setContentType(getContentType());if (logger.isDebugEnabled()) {logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");}rd.include(requestToExpose, 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(requestToExpose, response);}}

 第六种:返回类型是Void

这时我们需要考虑两个问题,第一:返回值是Void也就是没有返回值,他的ModalAndView对象是什么样的?第二:他将转到哪个页面,还是会直接报错?

带着这两个问题,我们看源码:

以DispatcherServlet中的这句代码往下看,

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

一直到ServletInvocableHandlerMethod类的这个方法

public final void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest); if (returnValue == null) {if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(this.responseReason)) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);try {
       //主要看这里,handleReturnValue,处理返回值,那我们点进去看看他怎么处理null值
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;}}

然而结果就是他看到return是null,什么都没处理就返回了,只好再往下看。

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()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}}//最后发现view为null时,这里处理了 applyDefaultViewName(request, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Error err) {triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}

接下来是组装地址的方法:这个是处理地址组装的类UrlBasedViewResolver

@Overrideprotected View loadView(String viewName, Locale locale) throws Exception {
     //进行组装 AbstractUrlBasedView view
= buildView(viewName);View result = applyLifecycleMethods(viewName, view);return (view.checkResource(locale) ? result : null);}
protected AbstractUrlBasedView buildView(String viewName) throws Exception {AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
     //对应的我最上方spring.mvc里面的prefix和suffix的配置的地址,把它们连接起来 view.setUrl(getPrefix()
+ viewName + getSuffix());String contentType = getContentType();if (contentType != null) {view.setContentType(contentType);}view.setRequestContextAttribute(getRequestContextAttribute());view.setAttributesMap(getAttributesMap());if (this.exposePathVariables != null) {view.setExposePathVariables(exposePathVariables);}return view;}

到此,要转向哪一个地址,ModelAndView对象是什么样都已经大致清楚了。然后就是调用rd.forward(requestToExpose, response);方法,渲染到页面

 

里面代码很多,思路也不是很清楚。有意义的地方只是给小伙伴们提供了几个方向,要想看springMvc是如何渲染视图的,可以从他的返回类型入手,然后debug一步步的看。源码我是在这里:

https://mvnrepository.com/search?q=spring-ui&p=2     下载的。我这里用的是4.0.0的版本。最后在总结一下吧。

首先,要构造一个ModelAndView对象,这个对象的构建思路是,我创建一个数组,把一个对象放在这个数组里,然后把数组给你,你往这个数组里放值,然后我去取这个数组里的值。然后获取的值我拿来

创建一个ModelAndView对象。

第二步,去渲染视图,有很多的渲染视图的处理器,系统会去判断选择一个处理器,来处理你的请求,大概的不同就是,我最终是调doFord还是doRedirect,我的返回值的header应该设置什么等等。

转载于:https://www.cnblogs.com/javammc/p/8570823.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

山西计算机工程师职称英语,山西中级工程师职称在线查询

技校网专门为您推荐的类似问题答案问题1&#xff1a;新疆石河子中级工程师职称在哪查询应该还没出&#xff0c;这里说不定有吧。。。不确定~问题2&#xff1a;武汉市中级工程师职称如何办理楼主,看你是要办那个对方的,现在大多数市面上都是随州办理的 比较容易办到 还有专科毕业…

spring3: 切面及通知实例 Aspectj的aop

1.前置通知 接口&#xff1a; package chapter1.server;public interface IHelloService {public void sayAdvisorBefore(String param) ; }实现 package chapter1.service.impl;import chapter1.server.IHelloService;public class HelloService implements IHelloService { p…

微型计算机接口与技术期末,微机原理与接口技术期末考试试题及答案.pdf

微机原理与接口技术期末考试题库1. 微机系统的硬件由哪几部分组成&#xff1f;答&#xff1a;三部分&#xff1a;微型计算机 (微处理器&#xff0c;存储器&#xff0c;I/0接口&#xff0c;系统总线)&#xff0c;外围设备&#xff0c;电源。2. 什么是微机的总线&#xff0c;分为…

html对图片轮播脚本怎么调用,【jquery前端开发】可调整的幻灯片(图片轮播)

第一次写博客&#xff0c;希望接下来写的东西 或多或少能帮到些人&#xff0c;虽然这些东西都是一些大神前辈们写了无数遍的东西&#xff0c;但我尽量以一名小白的视角把代码写得清楚点&#xff0c;好心人的就给点赞吧。1.前期准备这是我们编写代码前必须要做的事&#xff0c;在…

数据类型总结(干货)

Java中的数据类型和C的数据类型基本是一致的&#xff0c;本来以为不需要怎么看&#xff0c;后来发现还是有些地方需要好好总结一下。 基本的就不说了&#xff0c;直接上干货。 我总结了下&#xff0c;数据类型的转换和赋值有以下几点是比较麻烦的&#xff1a; 1、整数直接量可以…

计算机主机信息怎么看,本机电脑硬件配置信息怎么看?Win7/Win10查看详细电脑配置方法...

电脑配置决定了一台电脑的性能好坏&#xff0c;如果电脑配置没有达到游戏或者软件的要求&#xff0c;那么肯定无法流畅运行的。对于一些小白用户不知道如何查看电脑硬件配置&#xff0c;那么本机电脑硬件配置信息怎么看&#xff1f;下面装机之家小编分享一下Win7/Win10查看详细…

软件工程网络15个人阅读作业2(201521123024丁树乐)

提出问题 question1.我看到书P27中写到“100%的代码覆盖率并不等同于100%的正确性”那么怎么样去确保100%的正确性&#xff1f; 写代码注意结构和代码规范&#xff0c;注释要写全&#xff0c;代码尽量精简&#xff0c;不要一坨坨的堆在一起。 在目前行业内的成熟方案有如下几个…

Uva 1025 - A Spy in the Metro(DP)

题目链接 https://vjudge.net/problem/UVA-1025 【题意】 某城市里的地铁是线性的&#xff0c;有n个车站&#xff08;2<n<50&#xff09;&#xff0c;有M1辆列车从第1站从左往右开&#xff0c;有M2辆列车从第n站从右往左开&#xff0c;在0时刻间谍从第一站出发&a…

未来计算机控制器趋势,未来DCS控制系统技术发展4大趋势

DCS系统是继PLC之外的一大自动化控制系统&#xff0c;它在化工、火电等领域的应用极为广泛&#xff0c;但是生产方面的自动化技术需求进一步提高&#xff0c;传统的DCS系统已不能满足需要&#xff0c;需要进行技术升级。DCS系统由多台计算机分别控制生产过程中多个控制回路&…

《Java技术》第一次作业

&#xff08;一&#xff09;、学习总结 1.在java中通过Scanner类完成控制台的输入&#xff0c;查阅JDK帮助文档&#xff0c;Scanner类实现基本数据输入的方法是什么&#xff1f;不能只用文字描述&#xff0c;一定要写代码&#xff0c;通过具体实例加以说明。 文本扫描类Scanner…

计算机主机开机为什么显示器不开,电脑开机后显示器不亮怎么办?电脑开机后显示器没反应的解决办法...

电脑开机后显示器不亮怎么办&#xff1f;电脑开机故障屡见不鲜&#xff0c;最近又有用户反馈开机问题了&#xff0c;一用户反馈说&#xff0c;电脑主机是可以正常开机的&#xff0c;但就是显示器不亮&#xff0c;这是怎么回事呢&#xff1f;出现这种情况可能是显示器或主机故障…

斯坦福-随机图模型-week4.0_

title: 斯坦福-随机图模型-week4.0 tags: note notebook: 6- 英文课程-9-Probabilistic Graphical Models 1: Representation --- 斯坦福-随机图模型-week4.0 最大期望收入模型 简答的决策 我们使用随机图模型进行决策需要的原料是什么ne ? 我们需要决策的情景一些列的可能的行…

西北农林科技大学计算机老师 癌症,西北农林科大攻克苹果树“癌症”

由西北农林科技大学主持完成的“苹果树腐烂病等重大病害生物学及防治技术研究”项目&#xff0c;12月12日在陕西杨凌农科城通过鉴定。鉴定委员认为该成果在苹果树腐烂病菌、轮纹病菌的生物学基础研究方面达到了国际领先水平。我国苹果栽培面积和产量分别占世界总量的2/5和1/3&a…

计算机行业哪个会议论文最好,《第三次全国电子计算机专业学术会议论文选集》...

1964年12月&#xff0c;国防工业出版社出版了《第三次全国电子计算机专业学术会议论文选集》(以下简称《选集》)&#xff0c;由中国电子学会计算机专业委员会编辑&#xff0c;《选集》内容覆盖之广令人震惊。《选集》的内容表达了1961年以来国内计算技术在理论与实际方面的工作…

maven运行tomcat6出现错误Exception starting filter encodingFilter怎么解决

严重: Exception starting filter encodingFilterjava.lang.ClassCastException: org.springframework.web.filter.CharacterEncodingFilter cannot be cast to javax.servlet.Filterat org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.j…

windows系统OLLVM + NDK 混淆编译环境搭建

一、环境搭建&#xff1a; 系统&#xff1a;win10_X64 ndk版本&#xff1a;ndk-r12b&#xff08;ndk-r12b后续版本也适用&#xff09; cmake-3.9.1-win64-x64.msi 用于针对不同编译器生成源代码构建文件&#xff0c;如使用VS则生成(.sln)等VS配置文件&#xff0c;如果使用gcc则…

计算机组成实验微程序控制器实验,计算机组成原理实验报告3++微程序控制器实验.doc...

文档介绍&#xff1a;计算机组成原理实验报告3微程序控制器实验计算机组成原理实验报告实验三微程序控制器实验一.实验目的与要求:实验目的:1.理解时序产生器的原理,了解时钟和时序信号的波形;2.掌握微程序控制器的功能,组成知识;3.掌握微指令格式和各字段功能;4.掌握微程序的编…

展开符和解构赋值

一、展开符展开符(剩余操作符)&#xff1a;...1.展开符号use strict; let arr_one [1,3]; let arr_two [4,5,...arr_one]; console.log(arr_one);//[ 1, 3 ] console.log(...arr_one);//1 3 console.log(arr_two);//[ 4, 5, 1, 3 ]2.剩余操作符&#xff08;类似arguments&…

a开头的计算机语言,我们刚开始接触计算机语言大多从Hello world 开始

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼char szClassName[] "MainWnd";HINSTANCE hInstance;int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){HWND hwnd;MSG msg;WNDCLASSEX wincl;hInstance hInst;wincl.cbS…

2.1 linux C 进程与多线程入门--(1)进程和程序的区别

进程和程序的区别: j进程是活动的程序&#xff0c;而程序是一个代码的集合。进程是加载到内存中的程序&#xff0c;而程序没有加载到内存中&#xff0c;只是在磁盘上存储着。 1234567891011121314151617181920212223242526272829303132#include<sys/types.h>#include<…