【转载】SpringMVC学习笔记

转载于:SpringMVC笔记

SpringMVC

1.SpringMVC概述

MVC:

  • Model(模型): 数据模型,提供要展示的数据,:Value Object(数据Dao) 和 服务层(行为Service),提供数据和业务。

  • View(视图): 负责进行模型的展示,即用户界面

  • Controller(控制器): 调度员,接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。

SpringMVC的特点:

  • Spring为展现层提供的基于MVC设计理念的Web框架

  • SpirngMVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须实现任何接口

  • 支持REST风格的URL请求

  • 采用了松散耦合可拔插组件结构,扩展性和灵活性

2. HelloWorld

1. 导入依赖

spring-webmvc的maven依赖

&lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 核心包--&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-beans&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-core&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-expression&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 日志包--&gt; &lt;dependency&gt; &lt;groupId&gt;commons-logging&lt;/groupId&gt; &lt;artifactId&gt;commons-logging&lt;/artifactId&gt; &lt;version&gt;1.1.3&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 注解支持包--&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-aop&lt;/artifactId&gt; &lt;version&gt;4.0.0.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt;</pre> DispatcherServlet &lt;!--注册DispatcherServlet,请求分发器(前端控制器)--&gt; &lt;servlet&gt; &lt;servlet-name&gt;springDispatcherServlet&lt;/servlet-name&gt; &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt; &lt;!--绑定Spring配置文件--&gt; &lt;init-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt;classpath:springmvc-config.xml&lt;/param-value&gt; &lt;/init-param&gt; &lt;!--启动级别为1,即服务器启动后就启动--&gt; &lt;!--值越小优先级越高,越先创建对象--&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; &lt;!-- / 拦截所有的请求;(不包括.jsp,jsp由Tomcat来处理), 覆盖了父类的DispatcherServlet的pattern,静态资源被拦截。--&gt; &lt;!-- *.jsp 拦截jsp请求,覆盖了父类的JspServlet--&gt; &lt;!-- /* 拦截所有的请求;(包括.jsp,一旦拦截jsp页面就不能显示了)--&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;springDispatcherServlet&lt;/servlet-name&gt; &lt;url-pattern&gt;/&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; InternalResourceViewResolver &lt;!--开启包扫描,让指定包下的注解生效,由IOC容器统一管理--&gt; &lt;context:component-scan base-package="com.xiao.controller"/&gt; &lt;!--配置视图解析器,拼接视图名字,找到对应的视图--&gt; &lt;bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; &lt;!--前缀--&gt; &lt;property name="prefix" value="/WEB-INF/page/"/&gt; &lt;!--后缀--&gt; &lt;property name="suffix" value=".jsp"/&gt; &lt;/bean&gt; @RequestMapping("/hello01") public String toSuccess(){ System.out.println("请求成功页面"); return "success"; } @RequestMapping("/hello02") public String toError() { System.out.println("请求错误页面"); return "error"; } @RequestMapping("/hello01") / /haha/hello01 dispatcherServlet-servlet.xml url-pattern=/ @RequestParam required=false defaultValue @RequestHeader @CookieValue ${requestScope.reqParam} @SessionAttributes @SessionAttributes(value = "msg") @SessionAttributes(types = {String.class}) @ModelAttribute if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map&lt;String, HandlerMapping&gt; matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList&lt;HandlerMapping&gt;(matchingBeans.values()); // We keep HandlerMappings in sorted order. OrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }</pre> //1、检查是否文件上传请求 processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //2、根据当前的请求地址找到那个类能来处理; mappedHandler = getHandler(processedRequest); //3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常 if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //4、拿到能执行这个类的所有方法的适配器;(反射工AnnotationMethodHandlerAdapter) 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) &amp;&amp; isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler.处理(控制)器的方法被调用 //控制器(Controller),处理器(Handler) //5、适配器来执行目标方法; //将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView中 //目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView mv = ha.handle(processedRequest,response,mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv);//如果没有视图名设置一个默认的视图名; mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //转发到目标页面; //6、根据方法最终执行完成后封装的ModelAndView; //转发到对应页面,而且ModelAndView中的数据可以从请求域中获取 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); } } }</pre> ExtendedModelMap implicitModel = new BindingAwareModelMap();//**重点 //真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行modelattribute等所有的操作都在这个方法中; Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); //=======================看后边补充的代码块=========================== ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); return mav; }</pre> //找到所有@ModelAttribute注解标注的方法; for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); //先确定modelattribute方法执行时要使用的每一个参数的值; Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); //==========================看后边补充的代码块===================================== if (debug) { logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); } String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); if (!"".equals(attrName) &amp;&amp; implicitModel.containsAttribute(attrName)) { continue; } ReflectionUtils.makeAccessible(attributeMethodToInvoke); //提前运行ModelAttribute, Object attrValue = attributeMethodToInvoke.invoke(handler, args); if ("".equals(attrName)) { Class&lt;?&gt; resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); } /* 方法上标注的ModelAttribute注解如果有value值 @ModelAttribute("abc") hahaMyModelAttribute() 标了: attrName="abc" 没标: attrName="";attrName就会变为返回值类型首字母小写, 比如void ,或者book; @ModelAttribute标在方法上的另外一个作用; 可以把方法运行后的返回值按照方法上@ModelAttribute("abc") 指定的key放到隐含模型中; 如果没有指定这个key;就用返回值类型的首字母小写 { haha=Book [id=100, bookName=西游记, author=吴承恩, stock=98, sales=10, price=98.98], void=null } */ //把提前运行的ModelAttribute方法的返回值也放在隐含模型中 if (!implicitModel.containsAttribute(attrName)) { implicitModel.addAttribute(attrName, attrValue); } } //再次解析目标方法参数是哪些值 Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking request handler method: " + handlerMethodToInvoke); } ReflectionUtils.makeAccessible(handlerMethodToInvoke); //执行目标方法 return handlerMethodToInvoke.invoke(handler, args); } catch (IllegalStateException ex) { // Internal assertion failed (e.g. invalid signature): // throw exception with full handler method context... throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); } catch (InvocationTargetException ex) { // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... ReflectionUtils.rethrowException(ex.getTargetException()); return null; } }</pre> for (int i = 0; i &lt; args.length; i++) { MethodParameter methodParam = new MethodParameter(handlerMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; String headerName = null; boolean requestBodyFound = false; String cookieName = null; String pathVarName = null; String attrName = null; boolean required = false; String defaultValue = null; boolean validate = false; Object[] validationHints = null; int annotationsFound = 0; Annotation[] paramAnns = methodParam.getParameterAnnotations(); //找到目标方法这个参数的所有注解,如果有注解就解析并保存注解的信息; for (Annotation paramAnn : paramAnns) { if (RequestParam.class.isInstance(paramAnn)) { RequestParam requestParam = (RequestParam) paramAnn; paramName = requestParam.value(); required = requestParam.required(); defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); annotationsFound++; } else if (RequestHeader.class.isInstance(paramAnn)) { RequestHeader requestHeader = (RequestHeader) paramAnn; headerName = requestHeader.value(); required = requestHeader.required(); defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); annotationsFound++; } else if (RequestBody.class.isInstance(paramAnn)) { requestBodyFound = true; annotationsFound++; } else if (CookieValue.class.isInstance(paramAnn)) { CookieValue cookieValue = (CookieValue) paramAnn; cookieName = cookieValue.value(); required = cookieValue.required(); defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); annotationsFound++; } else if (PathVariable.class.isInstance(paramAnn)) { PathVariable pathVar = (PathVariable) paramAnn; pathVarName = pathVar.value(); annotationsFound++; } else if (ModelAttribute.class.isInstance(paramAnn)) { ModelAttribute attr = (ModelAttribute) paramAnn; attrName = attr.value(); annotationsFound++; } else if (Value.class.isInstance(paramAnn)) { defaultValue = ((Value) paramAnn).value(); } else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) { validate = true; Object value = AnnotationUtils.getValue(paramAnn); validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value}); } } if (annotationsFound &gt; 1) { throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + "do not specify more than one such annotation on the same parameter: " + handlerMethod); } //没有找到注解的情况; if (annotationsFound == 0) { //解析普通参数 Object argValue = resolveCommonArgument(methodParam, webRequest); //=====================看后边补充的代码块========================= //会进入resolveStandardArgument(解析标准参数) if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else if (defaultValue != null) { args[i] = resolveDefaultValue(defaultValue); } else { //判断是否是Model或者是Map旗下的,如果是将之前创建的隐含模型直接赋值给这个参数 Class&lt;?&gt; paramType = methodParam.getParameterType(); if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { if (!paramType.isAssignableFrom(implicitModel.getClass())) { throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " + "Model or Map but is not assignable from the actual model. You may need to switch " + "newer MVC infrastructure classes to use this argument."); } args[i] = implicitModel; } else if (SessionStatus.class.isAssignableFrom(paramType)) { args[i] = this.sessionStatus; } else if (HttpEntity.class.isAssignableFrom(paramType)) { args[i] = resolveHttpEntityRequest(methodParam, webRequest); } else if (Errors.class.isAssignableFrom(paramType)) { throw new IllegalStateException("Errors/BindingResult argument declared " + "without preceding model attribute. Check your handler method signature!"); } else if (BeanUtils.isSimpleProperty(paramType)) { paramName = ""; } else { attrName = ""; } } } //确定值的环节 if (paramName != null) { args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); } else if (headerName != null) { args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); } else if (requestBodyFound) { args[i] = resolveRequestBody(methodParam, webRequest, handler); } else if (cookieName != null) { args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); } else if (pathVarName != null) { args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); } //确定自定义类型参数的值;还要将请求中的每一个参数赋值给这个对象 else if (attrName != null) { WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); //=====================看后边代码补充============================ boolean assignBindingResult = (args.length &gt; i + 1 &amp;&amp; Errors.class.isAssignableFrom(paramTypes[i + 1])); if (binder.getTarget() != null) { doBind(binder, webRequest, validate, validationHints, !assignBindingResult); } args[i] = binder.getTarget(); if (assignBindingResult) { args[i + 1] = binder.getBindingResult(); i++; } implicitModel.putAll(binder.getBindingResult().getModel()); } } return args; }</pre> if (ServletRequest.class.isAssignableFrom(parameterType) || MultipartRequest.class.isAssignableFrom(parameterType)) { Object nativeRequest = webRequest.getNativeRequest(parameterType); if (nativeRequest == null) { throw new IllegalStateException( "Current request is not of type [" + parameterType.getName() + "]: " + request); } return nativeRequest; } else if (ServletResponse.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; Object nativeResponse = webRequest.getNativeResponse(parameterType); if (nativeResponse == null) { throw new IllegalStateException( "Current response is not of type [" + parameterType.getName() + "]: " + response); } return nativeResponse; } else if (HttpSession.class.isAssignableFrom(parameterType)) { return request.getSession(); } else if (Principal.class.isAssignableFrom(parameterType)) { return request.getUserPrincipal(); } else if (Locale.class.equals(parameterType)) { return RequestContextUtils.getLocale(request); } else if (InputStream.class.isAssignableFrom(parameterType)) { return request.getInputStream(); } else if (Reader.class.isAssignableFrom(parameterType)) { return request.getReader(); } else if (OutputStream.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getOutputStream(); } else if (Writer.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getWriter(); } return super.resolveStandardArgument(parameterType, webRequest); }</pre> // Bind request parameter onto object... String name = attrName; if ("".equals(name)) { //如果attrName是空串;就将参数类型的首字母小写作为值 //Book book2121 -&gt; name=book name = Conventions.getVariableNameForParameter(methodParam); } Class&lt;?&gt; paramType = methodParam.getParameterType(); Object bindObject; //确定目标对象的值 if (implicitModel.containsKey(name)) { bindObject = implicitModel.get(name); } else if (this.methodResolver.isSessionAttribute(name, paramType)) { bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); if (bindObject == null) { raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); } } else { bindObject = BeanUtils.instantiateClass(paramType); } WebDataBinder binder = createBinder(webRequest, bindObject, name); initBinder(handler, name, binder, webRequest); return binder; }</pre> //遍历所有的ViewResolver; for (ViewResolver viewResolver : this.viewResolvers) { //viewResolver视图解析器根据方法的返回值,得到一个View对象; View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }</pre> // Ask the subclass to create the View object. //根据方法的返回值创建出视图View对象; view = createView(viewName, locale); if (view == null &amp;&amp; this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } return (view != UNRESOLVED_VIEW ? view : null); } }</pre> </li><li> <p>创建View对象</p> <p>&nbsp;</p> </li></ul><p>&nbsp;</p> <pre> @Override protected 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. 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. //如果没有前缀就使用父类默认创建一个View; return super.createView(viewName, locale); }</pre> <p>&nbsp;</p> <p>&nbsp;</p> Map&lt;String, Object&gt; mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); //渲染要给页面输出的所有数据 renderMergedOutputModel(mergedModel, request, response); }</pre> </li><li> <p>InternalResourceView有这个方法renderMergedOutputModel;</p> <pre>@Override protected void renderMergedOutputModel( Map&lt;String, Object&gt; 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); } }</pre> </li><li> <p>将模型中的所有数据取出来全放在request域中</p> <pre>protected void exposeModelAsRequestAttributes(Map&lt;String, Object&gt; model, HttpServletRequest request) throws Exception { for (Map.Entry&lt;String, Object&gt; entry : model.entrySet()) { String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { //将ModelMap中的数据放到请求域中 request.setAttribute(modelName, modelValue); if (logger.isDebugEnabled()) { logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + getBeanName() + "'"); } } else { request.removeAttribute(modelName); if (logger.isDebugEnabled()) { logger.debug("Removed model object '" + modelName + "' from request in view with name '" + getBeanName() + "'"); } } } }</pre> <p>总结:</p> <ul><li> <p>视图解析器只是为了得到视图对象</p> </li><li> <p>视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面视图对象才能真正的渲染视图</p> </li></ul></li><li> <p>ViewResolver</p> <p>&nbsp;</p> </li><li> <p>View:</p> <p>&nbsp;</p> </li></ul></li></ol> <fmt:setLocale> <fmt:setBundle> <fmt:message> <fmt:message> mvc:view-controller public void render(Map&lt;String, ?&gt; model, HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("保存的数据:"+model); response.getWriter().write("即将展现内容:"); } private Integer order = 0; public View resolveViewName(String viewName, Locale locale) throws Exception { if (viewName.startsWith("myView:")) { return new MyView(); } else { return null; } } public int getOrder() { return this.order; } public void setOrder(Integer order) { this.order = order; } &lt;context:component-scan base-package="com.chenhui"&gt;&lt;/context:component-scan&gt; &lt;bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; &lt;property name="prefix" value="/WEB-INF/pages/"&gt;&lt;/property&gt; &lt;property name="suffix" value=".jsp"&gt;&lt;/property&gt; &lt;/bean&gt; &lt;servlet&gt; &lt;servlet-name&gt;dispatcherServlet&lt;/servlet-name&gt; &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt; &lt;init-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt;classpath:ioc.xml&lt;/param-value&gt; &lt;/init-param&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;dispatcherServlet&lt;/servlet-name&gt; &lt;url-pattern&gt;/&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; &lt;filter&gt; &lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt; &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt; &lt;init-param&gt; &lt;param-name&gt;encoding&lt;/param-name&gt; &lt;param-value&gt;UTF-8&lt;/param-value&gt; &lt;/init-param&gt; &lt;init-param&gt; &lt;param-name&gt;forceEncoding&lt;/param-name&gt; &lt;param-value&gt;true&lt;/param-value&gt; &lt;/init-param&gt; &lt;/filter&gt; &lt;filter-mapping&gt; &lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt; &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;/filter-mapping&gt; &lt;filter&gt; &lt;filter-name&gt;HiddenHttpMethodFilter&lt;/filter-name&gt; &lt;filter-class&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/filter-class&gt; &lt;/filter&gt; &lt;filter-mapping&gt; &lt;filter-name&gt;HiddenHttpMethodFilter&lt;/filter-name&gt; &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;/filter-mapping&gt; private Integer id; private String lastName; private String email; //1 male, 0 female private Integer gender; private Department department; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Employee(Integer id, String lastName, String email, Integer gender, Department department) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; this.department = department; } public Employee() { } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", department=" + department + "]"; } private Integer id; private String lastName; private String email; //1 male, 0 female private Integer gender; private Department department; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Employee(Integer id, String lastName, String email, Integer gender, Department department) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; this.department = department; } public Employee() { } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", department=" + department + "]"; } private static Map&lt;Integer, Department&gt; departments = null; static{ departments = new HashMap&lt;Integer, Department&gt;(); departments.put(101, new Department(101, "D-AA")); departments.put(102, new Department(102, "D-BB")); departments.put(103, new Department(103, "D-CC")); departments.put(104, new Department(104, "D-DD")); departments.put(105, new Department(105, "D-EE")); } public Collection&lt;Department&gt; getDepartments(){ return departments.values(); } public Department getDepartment(Integer id){ return departments.get(id); } private static Map&lt;Integer, Employee&gt; employees = null; @Autowired private DepartmentDao departmentDao; static{ employees = new HashMap&lt;Integer, Employee&gt;(); employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA"))); employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB"))); employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC"))); employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD"))); employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE"))); } private static Integer initId = 1006; public void save(Employee employee){ if(employee.getId() == null){ employee.setId(initId++); } employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId())); employees.put(employee.getId(), employee); } public Collection&lt;Employee&gt; getAll(){ return employees.values(); } public Employee get(Integer id){ return employees.get(id); } public void delete(Integer id){ employees.remove(id); } @Autowired EmployeeDao employees; @Autowired DepartmentDao departments; @RequestMapping(value = "/emp", method = RequestMethod.GET) public String getEmps(Model model) { Collection&lt;Employee&gt; all = employees.getAll(); model.addAttribute("emps", all); return "list"; } @RequestMapping(value = "/emp", method = RequestMethod.POST) public String addEmp(Employee employee, Model model) { employees.save(employee); return "redirect:/emp"; } @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET) public String getEmp(@PathVariable("id") Integer id, Model model) { Employee employee = employees.get(id); Collection&lt;Department&gt; departments = this.departments.getDepartments(); //此处给spring表单添加一个employee对象,以免发生command未找到的异常 model.addAttribute("employee", employee); model.addAttribute("departments", departments); return "editEmp"; } @RequestMapping(value = "/emp/{id}", method = RequestMethod.PUT) public String updateEmp(@ModelAttribute("employee") Employee employee, @PathVariable("id") Integer integer) { System.out.println("要修改的:" + employee); employees.save(employee); return "redirect:/emp"; } @RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE) public String deleteEmp(@PathVariable("id") Integer id) { employees.delete(id); return "redirect:/emp"; } @ModelAttribute public void myMethodAttribute(@RequestParam(value = "id", required = false) Integer id, Model model) { System.out.println("modelAttribute"); if (id != null) { Employee employee = employees.get(id); model.addAttribute("employee", employee); } } @RequestMapping("/toaddpage") public String toAddPage(Model model) { Collection&lt;Department&gt; all = departments.getDepartments(); model.addAttribute("departments", all); model.addAttribute("command", new Employee()); return "addEmp"; } private Department department;--%&gt; &lt;thead&gt; &lt;tr&gt; &lt;th&gt;ID&lt;/th&gt; &lt;th&gt;lastName&lt;/th&gt; &lt;th&gt;email&lt;/th&gt; &lt;th&gt;gender&lt;/th&gt; &lt;th&gt;departmentName&lt;/th&gt; &lt;th&gt;EDIT&lt;/th&gt; &lt;th&gt;DELETE&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;c:forEach items="${emps}" var="emp"&gt; &lt;tr&gt; &lt;td&gt;${emp.id}&lt;/td&gt; &lt;td&gt;${emp.lastName}&lt;/td&gt; &lt;td&gt;${emp.email}&lt;/td&gt; &lt;td&gt;${emp.gender==0?"女":"男"}&lt;/td&gt; &lt;td&gt;${emp.department.departmentName}&lt;/td&gt; &lt;td&gt;&lt;a href="${ctp}/emp/${emp.id}"&gt;修改&lt;/a&gt;&lt;/td&gt; &lt;!--删除操作可以绑定单击事件,使用ajax发送delete请求--&gt; &lt;td&gt; &lt;form action="${ctp}/emp/${emp.id}" method="post"&gt; &lt;input type="hidden" name="_method" value="DELETE"&gt; &lt;input type="submit" value="delete"&gt; &lt;/form&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/c:forEach&gt; &lt;/tbody&gt; model.addAttribute("departments", all); model.addAttribute("command", new Employee()); return "addEmp"; }</pre> 姓名:&lt;form:input path="lastName"&gt;&lt;/form:input&gt;&lt;br&gt; 邮箱:&lt;form:input path="email"&gt;&lt;/form:input&gt;&lt;br&gt; 性别:&lt;br&gt; 男:&lt;form:radiobutton path="gender" value="1"&gt;&lt;/form:radiobutton&gt; 女:&lt;form:radiobutton path="gender" value="0"&gt;&lt;/form:radiobutton&gt;&lt;br&gt; 部门: &lt;form:select path="department.id" items="${departments}" itemLabel="departmentName" itemValue="id"&gt; &lt;/form:select&gt; &lt;input type="submit" value="修改"&gt; //WebDataBinder WebDataBinder binder = binderFactory.createBinder(request, attribute, name); if (binder.getTarget() != null) { //将页面提交过来的数据封装到javaBean的属性中 bindRequestParameters(binder, request); //+++++++++ validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors()) { if (isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } } @Autowired DepartmentDao departmentDao; public Employee convert(String source) { System.out.println("将要转换的字符串" + source); Employee employee = new Employee(); if (source.contains("-")) { String[] split = source.split("-"); employee.setLastName(split[0]); employee.setEmail(split[1]); employee.setGender(Integer.parseInt(split[2])); employee.setDepartment(departmentDao.getDepartment(Integer.parseInt(split[3]))); } return employee; } <mvc:default-servlet-handler/> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <mvc:annotation-driven/> <mvc:annotation-driven/> &lt;dependency&gt; &lt;groupId&gt;org.hibernate&lt;/groupId&gt; &lt;artifactId&gt;hibernate-validator&lt;/artifactId&gt; &lt;version&gt;5.4.1.Final&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.jboss.logging&lt;/groupId&gt; &lt;artifactId&gt;jboss-logging&lt;/artifactId&gt; &lt;version&gt;3.3.0.Final&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.fasterxml&lt;/groupId&gt; &lt;artifactId&gt;classmate&lt;/artifactId&gt; &lt;version&gt;1.3.3&lt;/version&gt; &lt;/dependency&gt;</pre> @DateTimeFormat(pattern = "yyyy-MM-dd") @Past private Date birth; if (result.hasErrors()){ System.out.println("有校验错误"); return "addEmp"; }else{ employees.save(employee); } return "redirect:/emp"; }</pre> @ResponseBody @RequestMapping("/getallajax") public Collection&lt;Employee&gt; ajaxGetAll() { Collection&lt;Employee&gt; all = employeeDao.getAll(); return all; } private String email; //1 male, 0 female private Integer gender; @JsonIgnore private Department department;</pre> <p>输入:</p> <p>&nbsp;</p> <p>结果:</p> <p>&nbsp;</p> </li></ul> System.out.println("上传信息"); System.out.println("文件名"+file.getName()); System.out.println("文件初始名"+file.getOriginalFilename()); try { file.transferTo(new File("D:\\upload\\"+file.getOriginalFilename())); model.addAttribute("message","文件上传成功"); } catch (IOException e) { e.printStackTrace(); model.addAttribute("message","文件上传失败"+e.getCause()); } return "list"; } for(MultipartFile file: files){ System.out.println("上传信息"); System.out.println("文件名"+file.getName()); System.out.println("文件初始名"+file.getOriginalFilename()); if(!file.isEmpty()){ try { file.transferTo(new File("D:\\upload\\"+file.getOriginalFilename())); model.addAttribute("message","文件上传成功"); } catch (IOException e) { e.printStackTrace(); model.addAttribute("message","文件上传失败"+e.getCause()); } } return "list"; } } public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyFirstInterceptor...preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyFirstInterceptor...postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyFirstInterceptor...afterCompletion"); } &lt;!--拦截具体请求↓--&gt; &lt;mvc:interceptor&gt; &lt;!--只拦截path所对应的请求--&gt; &lt;mvc:mapping path="/testInter"/&gt; &lt;bean class="com.chenhui.interceptor.MyFirstInterceptor"&gt;&lt;/bean&gt; &lt;/mvc:interceptor&gt; &lt;/mvc:interceptors&gt;</pre> <p>testInter控制器如下</p> <pre>@Controller @RequestMapping("/testInter") public String testInterceptor(){ return "hello"; } 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) &amp;&amp; isGet) { return; } } //拦截器preHandle执行位置;有一个拦截器返回false目标方法以后都不会执行;直接跳到afterCompletion if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler.适配器执行目标方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); //目标方法只要正常就会走到postHandle;任何期间有异常 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //页面渲染;如果完蛋也是直接跳到afterCompletion; 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); } } }</pre> //preHandle-true-false if (!interceptor.preHandle(request, response, this.handler)) { //执行完afterCompletion(); triggerAfterCompletion(request, response, null); //返回一个false return false; } //记录一下索引 //this.interceptorIndex = i; } } return true; }</pre> 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); } } // Did the handler return a view to render? if (mv != null &amp;&amp; !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) { //页面正常执行afterCompletion;即使没走到这,afterCompletion总会执行; mappedHandler.triggerAfterCompletion(request, response, null); } }</pre> if (getInterceptors() == null) { return; } //有记录最后一个放行拦截器的索引,从他开始把之前所有放行的拦截器的afterCompletion都执行 for (int i = this.interceptorIndex; i &gt;= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } }</pre> String locale = request.getParameter("locale"); System.out.println("自己区域解析器接受的locale:"+locale); if (locale != null &amp;&amp; !"".equals(locale)) { l = new Locale(locale.split("_")[0], locale.split("_")[1]); } else { l = request.getLocale(); } System.out.println("Locale:"+l.toString()); return l; } public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { throw new UnsupportedOperationException("Can't set Locale message"); } @Override public LocaleContext resolveLocaleContext(HttpServletRequest request) { return new TimeZoneAwareLocaleContext() { @Override public Locale getLocale() { return getDefaultLocale(); } @Override public TimeZone getTimeZone() { return getDefaultTimeZone(); } }; } @Override public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) { throw new UnsupportedOperationException("Cannot change fixed locale - use a different locale resolution strategy"); }</pre> 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); } } // Did the handler return a view to render? if (mv != null &amp;&amp; !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); } }</pre> // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } if (exMv != null) { if (exMv.isEmpty()) { return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { exMv.setViewName(getDefaultViewName(request)); } 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; } @ExceptionHandler(value = {ArithmeticException.class}) public String handleException01(){ System.out.println("handleException-Arithmetic"); return "myError"; } } System.out.println("登陆成功"); return "success"; }</pre>

__EOF__

本文作者Curryxin
本文链接https://www.cnblogs.com/Curryxin/p/15023785.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Curryxin  阅读(57)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『【转载】SpringMVC学习笔记』
点击右上角即可分享
微信分享提示