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

解析ModelAndView

一. RequestMappingHandlerAdapter类invokeHandlerMethod()方法

在RequestMappingHandlerAdapter#invokeHandlerMethod()方法中

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

在这里插入图片描述

	@Nullable
	protected 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()方法

在这里插入图片描述

	@Override
	public 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() 方法

在这里插入图片描述

在这里插入图片描述

	@Override
	public 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());
		//设置数据Model
		mavContainer.addAllAttributes(mav.getModel());
	}

五. RequestMappingHandlerAdapter类中的getModelAndView()方法

从ModelAndViewContainer容器中获取ModeAndView实例

在这里插入图片描述

	@Nullable
	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
		// 1.更新模型
		modelFactory.updateModel(webRequest, mavContainer);
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		// 2.获取ModelMap并创建ModelAndView
		ModelMap 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()方法

在这里插入图片描述

	@Nullable
	protected 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对象
	@Nullable
	View 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
	@Nullable
	default String getContentType() {
		return null;
	}


	//通过用户提供的模型数据与视图信息渲染视图
	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;

}

十. DispatcherServlet类中的resolveViewName()方法

	//根据视图名称创建View实例
	@Nullable
	protected 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 {
			//如果缓存可用, 则先尝试从缓存中获取
			//生成缓存Key
			Object 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是
						// 一个没有任何内容的View
						view = 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()方法

在这里插入图片描述

	@Override
	protected 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()方法

在这里插入图片描述


在这里插入图片描述

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

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

在这里插入图片描述

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		//对于InternalResourceViewResolver而言,其返回的View对象的具体类型是InternalResourceView
		Class<?> 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;
	}

在这里插入图片描述

	@Override
	public 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()方法

在这里插入图片描述

在这里插入图片描述

	@Override
	protected 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 的RequestDispatcher
		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!");
		}
		// 判断当前是否为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);
		}
	}

视图解析分析完成

原文地址:https://blog.csdn.net/weixin_45480785/article/details/116596262

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


开发过程中是不可避免地会出现各种异常情况的,例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题,甚至直接导致程序崩溃。因此,在开发过程中,合理处理异常、避免异常产生、以及对异常进行有效的调试是非常重要的。 对于异常的处理,一般分为两种方式: 编程式异常处理:是指在代
说明:使用注解方式实现AOP切面。 什么是AOP? 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能。 AOP底层使用动态代理。 AOP术语 连接点
Spring MVC中的拦截器是一种可以在请求处理过程中对请求进行拦截和处理的机制。 拦截器可以用于执行一些公共的操作,例如日志记录、权限验证、数据转换等。在Spring MVC中,可以通过实现HandlerInterceptor接口来创建自定义的拦截器,并通过配置来指定拦截器的应用范围和顺序。 S
在 JavaWeb 中,共享域指的是在 Servlet 中存储数据,以便在同一 Web 应用程序的多个组件中进行共享和访问。常见的共享域有四种:ServletContext、HttpSession、HttpServletRequest、PageContext。 ServletContext 共享域:
文件上传 说明: 使用maven构建web工程。 使用Thymeleaf技术进行服务器页面渲染。 使用ResponseEntity实现下载文件的功能。 @Controller public class FileDownloadAndUpload { @GetMapping(&quot;/file/d
创建初始化类,替换web.xml 在Servlet3.0环境中,Web容器(Tomcat)会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。 Spring提供了这个接口的实现,名为SpringS
在 Web 应用的三层架构中,确保在表述层(Presentation Layer)对数据进行检查和校验是非常重要的。正确的数据校验可以确保业务逻辑层(Business Logic Layer)基于有效和合法的数据进行处理,同时将错误的数据隔离在业务逻辑层之外。这有助于提高系统的健壮性、安全性和可维护
什么是事务? 事务(Transaction)是数据库操作最基本单元,逻辑上一组操作,要么都成功,要么都失败,如果操作之间有一个失败所有操作都失败 。 事务四个特性(ACID) 原子性 一组操作要么都成功,要么都失败。 一致性 一组数据从事务1合法状态转为事务2的另一种合法状态,就是一致。 隔离性 事
什么是JdbcTemplate? Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作。 准备工作 引入jdbcTemplate的相关依赖: 案例实操 创建jdbc.properties文件,配置数据库信息 jdbc.driver=com.mysql.cj.
SpringMVC1.MVC架构MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范是将业务逻辑、数据、显示分离的方法来写代码MVC主要作用是:降低了视图和业务逻辑之间的双向耦合MVC是一个架构模型,不是一种设计模式。1.model(模型)数据模型,提供要展示的数据,因此包
SpringMVC学习笔记1.SpringMVC应用1.1SpringMVC简介​SpringMVC全名叫SpringWebMVC,是⼀种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。​MVC全名是ModelViewController,是模型(model)-视图(view)-控制器(co
11.1数据回显基本用法数据回显就是当用户数据提交失败时,自动填充好已经输入的数据。一般来说,如果使用Ajax来做数据提交,基本上是没有数据回显这个需求的,但是如果是通过表单做数据提交,那么数据回显就非常有必要了。11.1.1简单数据类型简单数据类型,实际上框架在这里没有
一、SpringMVC简介1、SpringMVC中重要组件DispatcherServlet:前端控制器,接收所有请求(如果配置/不包含jsp)HandlerMapping:解析请求格式的.判断希望要执行哪个具体的方法.HandlerAdapter:负责调用具体的方法.ViewResovler:视图解析器.解析结果,准备跳转到具体的物
1.它们主要负责的模块Spring主要应用于业务逻辑层。SpringMVC主要应用于表现层。MyBatis主要应用于持久层。2.它们的核心Spring有三大核心,分别是IOC(控制反转),DI(依赖注入)和AOP(面向切面编程)。SpringMVC的核心是DispatcherServlet(前端控制器)。MyBatis的核心是ORM(对
3.注解开发Springmvc1.使用注解开发要注意开启注解支持,2.注解简化了,处理映射器和处理适配器,只用去管视图解析器即可案例代码:1.web.xml,基本不变可以直接拿去用<!--调用DispatcherServlet--><servlet><servlet-name>springmvc</servlet-name>
拦截器概述SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。**过滤器与拦截器的区别:**拦截器是AOP思想的具体应用。过滤器servlet规范中的一部分,任何javaweb工程都可以使用
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="
学习内容:1、SSH&SSM2、Spring3、Struts2&SpringMVC4、Hibernate&MyBatis学习产出:1.SSH和SSM都是有Spring框架的,他们两个差不多。2.Spring分为四个模块,持久层,表示层,检测层,还有核心层,核心层分为2个关键核心功能。分别为,控制反转(IOC),依赖注入(DI),和面向切面编程
一、SpringMVC项目无法引入js,css的问题具体原因是css和js等被SpringMVC拦截了:解决方案:在spring-mvc.xml中配置<mvc:default-servlet-handler/><?xmlversion="1.0"encoding="UTF-8"?><beansxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
开发环境:Eclipse/MyEclipse、Tomcat8、Jdk1.8数据库:MySQL前端:JavaScript、jQuery、bootstrap4、particles.js后端:maven、SpringMVC、MyBatis、ajax、mysql读写分离、mybatis分页适用于:课程设计,毕业设计,学习等等系统介绍