SpringMVC源码学习(七)---解析ModelAndView

2023-10-09 05:20

本文主要是介绍SpringMVC源码学习(七)---解析ModelAndView,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

解析ModelAndView

  • 一. RequestMappingHandlerAdapter类invokeHandlerMethod()方法
  • 二. invokeAndHandle() 方法
  • 三. handleReturnValue()方法
  • 四. ModelAndViewMethodReturnValueHandler类中的handleReturnValue() 方法
  • 五. RequestMappingHandlerAdapter类中的getModelAndView()方法
  • 六. DispatcherServlet类中的processDispatchResult()方法
  • 七. DispatcherServlet类中的processHandlerException()方法
  • 八. DispatcherServlet类中的render()方法
  • 九. ViewResolver和View接口
  • 十. DispatcherServlet类中的resolveViewName()方法
  • 十一. AbstractCachingViewResolver类中的resolveViewName()方法
  • 十二. UrlBasedViewResolver类中的createView()方法
  • 十三. UrlBasedViewResolver类中的loadView()方法
  • 十四. UrlBasedViewResolver类中的buildView()方法
  • 十五. UrlBasedViewResolver类中的applyLifecycleMethods()方法
  • 十六. AbstractView类中的render()方法
  • 十七. InternalResourceView类中的renderMergedOutputModel()方法

一. RequestMappingHandlerAdapter类invokeHandlerMethod()方法

在RequestMappingHandlerAdapter#invokeHandlerMethod()方法中

  1. 执行处理器方法(HandlerMethod)
  2. 封装并返回ModelAndView实例

在这里插入图片描述

	@Nullableprotected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {//将Request和Response进行封装ServletWebRequest webRequest = new ServletWebRequest(request, response);try {//WebDataBinderFactory --> 工厂类,为目标对象创建一个WebDataBinder实例// 1.WebDataBinder继承了DataBinder类,为web请求提供了参数绑定服务WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);// 获取ModelFactory:// 2.ModelFactory可以协助控制器在调用方法之前初始化模型,并在调用之后更新模型ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);//  创建InvocableHandlerMethod实例,以及各个组件的配置;//  后面通过调用invokeAndHandle()方法执行处理器ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);// 4.尝试绑定参数、返回值解析器if (this.argumentResolvers != null) {invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}invocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);// 创建视图容器, 用于封装视图, 数据模型, 处理状态等信息ModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);// 6.异步请求相关AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();if (logger.isDebugEnabled()) {logger.debug("Found concurrent result value [" + result + "]");}invocableMethod = invocableMethod.wrapConcurrentResult(result);}// 7.调用Controller中的具体方法并处理返回值 执行处理器invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}// 8.返回ModelAndView对象return getModelAndView(mavContainer, modelFactory, webRequest);}finally {// 完成请求后续处理,并将当前请求置为未激活webRequest.requestCompleted();}}

二. invokeAndHandle() 方法

在这里插入图片描述

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 1.调用Controller中的具体方法Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);// 2.设置返回状态码setResponseStatus(webRequest);// 3.当前请求无返回值或者返回值中包含错误,则将请求完成标识设置为true并返回if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}// 4.当前请求有返回值且无错误信息,则将请求完成标识设置为false,并继续处理当前请求mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {// 选取合适的HandlerMethodReturnValueHandler,并处理返回值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;}}

三. handleReturnValue()方法

在这里插入图片描述

	@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {//根据返回值以及返回类型选择合适的返回值处理器, 对返回值进行解析HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}//解析结果handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}

四. ModelAndViewMethodReturnValueHandler类中的handleReturnValue() 方法

在这里插入图片描述

在这里插入图片描述

	@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// 当前请求返回值为null,无需处理,并且要将当前请求标记已处理if (returnValue == null) {mavContainer.setRequestHandled(true);return;}// 处理引用视图ModelAndView mav = (ModelAndView) returnValue;if (mav.isReference()) {String viewName = mav.getViewName();mavContainer.setViewName(viewName);if (viewName != null && isRedirectViewName(viewName)) {mavContainer.setRedirectModelScenario(true);}}// 处理普通视图(即我们已经制定了具体的View视图,而无需通过视图解析器再次解析)else {View view = mav.getView();mavContainer.setView(view);if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {mavContainer.setRedirectModelScenario(true);}}// 设置返回状态mavContainer.setStatus(mav.getStatus());//设置数据ModelmavContainer.addAllAttributes(mav.getModel());}

五. RequestMappingHandlerAdapter类中的getModelAndView()方法

从ModelAndViewContainer容器中获取ModeAndView实例

在这里插入图片描述

	@Nullableprivate ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {// 1.更新模型modelFactory.updateModel(webRequest, mavContainer);if (mavContainer.isRequestHandled()) {return null;}// 2.获取ModelMap并创建ModelAndViewModelMap model = mavContainer.getModel();ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());// 3.处理引用类型视图和转发类型视图if (!mavContainer.isViewReference()) {mav.setView((View) mavContainer.getView());}if (model instanceof RedirectAttributes) {Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);if (request != null) {RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);}}return mav;}

六. DispatcherServlet类中的processDispatchResult()方法

解析ModelAndView

在这里插入图片描述

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;//如果在解析过程中出现异常, 这里会对异常进行处理if (exception != null) {//如果是默认异常,则获取异常视图if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}//如果是自定义异常, 则获取异常处理器, 进行解析else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);//异常视图解析mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// 尝试解析视图和模型;// wasCleared:判断当前模型和视图是否已经被标识为清空,且当前视图和模型是否同时为空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()) {return;}// 处理注册的后置完成拦截器if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}}

processDispatchResult() 方法

  1. 如果出现异常,则解析异常视图
  2. 解析ModelAndView

七. DispatcherServlet类中的processHandlerException()方法

在这里插入图片描述

	@Nullableprotected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {//遍历所有的异常解析器, 尝试对异常进行解析, 如果解析成功,跳出循焕for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}//对于简单的错误模型,我们可能仍需要视图名称转换if (!exMv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {exMv.setViewName(defaultViewName);}}if (logger.isDebugEnabled()) {logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);}//设置错误请求的相关属性WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());return exMv;}throw ex;}

八. DispatcherServlet类中的render()方法

在这里插入图片描述

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// 确定请求的区域设置并将其应用于响应。Locale locale =(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());response.setLocale(locale);View view;// 获取视图名String viewName = mv.getViewName();if (viewName != null) {view = resolveViewName(viewName, mv.getModelInternal(), locale, request);if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() +"' in servlet with name '" + getServletName() + "'");}}// 获取到视图名,再次判断当前ModelAndView对象中是否包含真正的View对象,// 因为接下来需要调用View对象的render方法else {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 {// 设置返回状态码if (mv.getStatus() != null) {response.setStatus(mv.getStatus().value());}// 调用View对象的render方法完成视图解析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;}}

ModelAndView视图解析可以分为两个重要步骤:

  1. 根据视图名称创建View实例
  2. 根据View实例渲染视图

九. ViewResolver和View接口

在这里插入图片描述

public interface ViewResolver {// 通过逻辑视图名和用户地区信息生成View对象@NullableView resolveViewName(String viewName, Locale locale) throws Exception;}

在这里插入图片描述

public interface View {String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";String PATH_VARIABLES = View.class.getName() + ".pathVariables";String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";//获取返回值的contentType@Nullabledefault String getContentType() {return null;}//通过用户提供的模型数据与视图信息渲染视图void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)throws Exception;}

十. DispatcherServlet类中的resolveViewName()方法

	//根据视图名称创建View实例@Nullableprotected View resolveViewName(String viewName, @Nullable Map<String, Object> model,Locale locale, HttpServletRequest request) throws Exception {if (this.viewResolvers != null) {for (ViewResolver viewResolver : this.viewResolvers) {//这里的视图解析器就是我们在配置文件中配置的那个View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}}}return null;}

在这里插入图片描述

十一. AbstractCachingViewResolver类中的resolveViewName()方法

在这里插入图片描述

在这里插入图片描述

public View resolveViewName(String viewName, Locale locale) throws Exception {//判断缓存是否可用if (!isCache()) {//如果缓存不可用, 则直接创建视图return createView(viewName, locale);}else {//如果缓存可用, 则先尝试从缓存中获取//生成缓存KeyObject cacheKey = getCacheKey(viewName, locale);//尝试从缓存中获取视图View view = this.viewAccessCache.get(cacheKey);if (view == null) {//如果从缓存中获取视图失败, 则尝试从viewCreationCache缓存中获取synchronized (this.viewCreationCache) {//让子类创建View对象, 留给子类扩展[扩展开放,修改关闭原则]view = this.viewCreationCache.get(cacheKey);if (view == null) {// 这里cacheUnresolved指的是是否缓存默认的空视图,UNRESOLVED_VIEW是// 一个没有任何内容的Viewview = createView(viewName, locale);if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null) {//将创建的view视图加入缓存this.viewAccessCache.put(cacheKey, view);this.viewCreationCache.put(cacheKey, view);if (logger.isTraceEnabled()) {logger.trace("Cached view [" + cacheKey + "]");}}}}}return (view != UNRESOLVED_VIEW ? view : null);}}

十二. UrlBasedViewResolver类中的createView()方法

在这里插入图片描述

	@Overrideprotected View createView(String viewName, Locale locale) throws Exception {if (!canHandle(viewName, locale)) {return null;}// 检查特殊的"redirect:"前缀 REDIRECT_URL_PREFIX = "redirect:"// 如果是以"redirect:" 开头, 说明该视图是重定向if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl,isRedirectContextRelative(), isRedirectHttp10Compatible());String[] hosts = getRedirectHosts();if (hosts != null) {view.setHosts(hosts);}return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);}// 检查特殊的"forward:"前缀 FORWARD_URL_PREFIX = "forward:"// 如果是以"forward:" 开头, 说明该视图是请求转发if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());return new InternalResourceView(forwardUrl);}//如果是普通视图, 创建该视图视图return super.createView(viewName, locale);}

十三. UrlBasedViewResolver类中的loadView()方法

在这里插入图片描述
在这里插入图片描述

	@Overrideprotected View loadView(String viewName, Locale locale) throws Exception {// 使用逻辑视图名按照指定规则生成View对象AbstractUrlBasedView view = buildView(viewName);// 应用声明周期函数,也就是调用View对象的初始化函数和Spring用于切入bean创建的View result = applyLifecycleMethods(viewName, view);// 检查view的准确性,这里默认始终返回truereturn (view.checkResource(locale) ? result : null);}

十四. UrlBasedViewResolver类中的buildView()方法

在这里插入图片描述

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {//对于InternalResourceViewResolver而言,其返回的View对象的具体类型是InternalResourceViewClass<?> viewClass = getViewClass();Assert.state(viewClass != null, "No view class");// 使用反射生成InternalResourceView对象实例AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);//根据前缀和后缀拼接视图路径信息view.setUrl(getPrefix() + viewName + getSuffix());// 设置View的contentType属性String contentType = getContentType();if (contentType != null) {view.setContentType(contentType);}// 设置contextAttribute和attributeMap等属性view.setRequestContextAttribute(getRequestContextAttribute());view.setAttributesMap(getAttributesMap());// pathVariables表示request请求url中的属性,这里主要是设置是否将这些属性暴露到视图中Boolean exposePathVariables = getExposePathVariables();if (exposePathVariables != null) {view.setExposePathVariables(exposePathVariables);}// 这里设置的是是否将Spring的bean暴露在视图中,以供给前端调用Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();if (exposeContextBeansAsAttributes != null) {view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);}// 设置需要暴露给前端页面的bean名称String[] exposedContextBeanNames = getExposedContextBeanNames();if (exposedContextBeanNames != null) {view.setExposedContextBeanNames(exposedContextBeanNames);}return view;}

十五. UrlBasedViewResolver类中的applyLifecycleMethods()方法

在这里插入图片描述

十六. AbstractView类中的render()方法

	protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {ApplicationContext context = getApplicationContext();if (context != null) {// 对生成的View对象应用初始化方法,主要包括InitializingBean.afterProperties()和一些// Processor,Aware方法Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);if (initialized instanceof View) {return (View) initialized;}}return view;}

在这里插入图片描述

	@Overridepublic void render(@Nullable 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);}// 合并为一个Map对象,以供给后面对视图的渲染使用Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);// 判断当前View对象的类型是否为文件下载类型,如果是文件下载类型,则设置response的prepareResponse(request, response);// 开始view视图渲染以及数据输出整理 renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}

十七. InternalResourceView类中的renderMergedOutputModel()方法

在这里插入图片描述

在这里插入图片描述

	@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {// 将Model中的键值对数据全部写进RequestScope中exposeModelAsRequestAttributes(model, request);// 提供的一个hook方法,默认是空实现,用于用户进行request属性的自定义使用exposeHelpers(request);//确定请求分配器的路径String dispatcherPath = prepareForRendering(request, response);// 获取可应用于 forward/include 的RequestDispatcherRequestDispatcher 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!");}// 判断当前是否为include请求,如果是,则调用RequestDispatcher.include()方法进行文件引入if (useInclude(request, response)) {response.setContentType(getContentType());if (logger.isDebugEnabled()) {logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");}rd.include(request, response);}// 请求转发//使用forward跳转则后面的response输出则不会执行,而用include来跳转,//则include的servlet执行完后,再返回到原来的servlet执行response的输出(如果有)else {if (logger.isDebugEnabled()) {logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");}//如果当前不是include()请求,则直接使用forward请求将当前请求转发到目标文件路径中,从而渲染该视图rd.forward(request, response);}}

视图解析分析完成

这篇关于SpringMVC源码学习(七)---解析ModelAndView的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/170645

相关文章

51单片机学习记录———定时器

文章目录 前言一、定时器介绍二、STC89C52定时器资源三、定时器框图四、定时器模式五、定时器相关寄存器六、定时器练习 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出~ 提示:以下是本篇文章正文内容,下面案例可供参考 一、定时器介绍 定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。 定时器作用: 1.用于计数系统,可

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

[word] word设置上标快捷键 #学习方法#其他#媒体

word设置上标快捷键 办公中,少不了使用word,这个是大家必备的软件,今天给大家分享word设置上标快捷键,希望在办公中能帮到您! 1、添加上标 在录入一些公式,或者是化学产品时,需要添加上标内容,按下快捷键Ctrl+shift++就能将需要的内容设置为上标符号。 word设置上标快捷键的方法就是以上内容了,需要的小伙伴都可以试一试呢!

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

解析 XML 和 INI

XML 1.TinyXML库 TinyXML是一个C++的XML解析库  使用介绍: https://www.cnblogs.com/mythou/archive/2011/11/27/2265169.html    使用的时候,只要把 tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.