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

public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//调用处理器对应的处理器方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//设置响应状态,如果在调用处理器方法时发生了错误,用webRequest获取response对象并设置它的状态
setResponseStatus(webRequest); if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
//为TRUE标识请求已经结束
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
} mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
} @Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//遍历寻找能够处理中返回参数类型的处理器,如果没有找到就抛出异常,判断是否能够处理很简单就是调用处理器的support方法
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
} 现在以RequestResponseBodyMethodProcessor为例 这个处理器是判断当前方法上面是否有@ResponseBody,如果有就表示这个方法能够支持处理。@Override
public boolean supportsReturnType(MethodParameter returnType) {
//判断这个方法对应的类是否有@ResponseBody注解
return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
//判断这个方法上是否有@ResponseBody注解
returnType.getMethodAnnotation(ResponseBody.class) != null);
} @Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//设置requestHandled已经被处理
mavContainer.setRequestHandled(true); // Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, webRequest);
} protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//包装request和response对象
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
} protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//获取返回值的类型
Class<?> returnValueClass = getReturnValueType(returnValue, returnType);
//获取返回值的泛型类型,比如List<String>,那么泛型类型就String.class
Type returnValueType = getGenericType(returnType);
HttpServletRequest servletRequest = inputMessage.getServletRequest();
//获取浏览器能够接受的类型
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
//获取返回的类型
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass, returnValueType); if (returnValue != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + returnValueClass);
} Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
//寻找兼容的媒体类型
if (requestedType.isCompatibleWith(producibleType)) {
//保存两者中认为最好的类型作为兼容类型
compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
//如果兼容类型为空,并且方法返回值又不为空,那么抛出异常,找不到浏览器能够接受的返回类型
if (compatibleMediaTypes.isEmpty()) {
if (returnValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
} List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
//对类型进行排序
MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
//如果找到不是通配符的媒体类型就作为选择的媒体类型(就是非综合类型,那种不能表示到具体是哪一种类型的,比如MediaType.ALL)
selectedMediaType = mediaType;
break;
}
//如果媒体类型是all(就是所有类型)或者是application应用类类型,那么设置成流类型
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
} if (selectedMediaType != null) {
//去除权衡值,比如application/json;q=0.8,去除后变成application/json
selectedMediaType = selectedMediaType.removeQualityValue();
//遍历所有注册的消息转换器,这里和解析参数时是差不多的操作
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter) {
if (((GenericHttpMessageConverter<T>) messageConverter).canWrite(returnValueType,
returnValueClass, selectedMediaType)) {
//调用实现了ResponseBodyAdvice的controller,对值进行处理
returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (returnValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((GenericHttpMessageConverter<T>) messageConverter).write(returnValue,
returnValueType, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + returnValue + "] as \"" +
selectedMediaType + "\" using [" + messageConverter + "]");
}
}
return;
}
}
else if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (returnValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((HttpMessageConverter<T>) messageConverter).write(returnValue,
selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + returnValue + "] as \"" +
selectedMediaType + "\" using [" + messageConverter + "]");
}
}
return;
}
}
} if (returnValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
} //遍历实现了ResponseBodyAdvice的Controller
private <T> Object processBody(Object body, MethodParameter returnType, MediaType contentType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest request, ServerHttpResponse response) { for (ResponseBodyAdvice<?> advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) {
//判断是否支持,最后使用outputmessage写出到客户端
if (advice.supports(returnType, converterType)) {
body = ((ResponseBodyAdvice<T>) advice).beforeBodyWrite((T) body, returnType,
contentType, converterType, request, response);
}
}
return body;
} 处理完后返回。 再来看看ModelAndViewMethodReturnValueHandler是这么处理返回值的 @Override
public boolean supportsReturnType(MethodParameter returnType) {
//处理返回类型是ModelAndView的方法
return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
} @Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//如果返回值为空,那么设置请求结束
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
} ModelAndView mav = (ModelAndView) returnValue;
//判断视图名是否为String类型
if (mav.isReference()) {
//获取视图名称
String viewName = mav.getViewName();
//给视图容器设置视图名称
mavContainer.setViewName(viewName);
//如果是重定向视图名称,那么设置重定向表示为true,如果没有重新配置这个handler,并且设置自定的标识符,默认就是判断这个视图名是否以redirect:开头
if (viewName != null && isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else {
//如果视图不是String类型的,那么就是视图对象
View view = mav.getView();
mavContainer.setView(view);
//判断是否是smartView,如果是,再判断是否是重定向视图,如果是就设置重定向标识
if (view instanceof SmartView) {
if (((SmartView) view).isRedirectView()) {
mavContainer.setRedirectModelScenario(true);
}
}
}
//将ModelAndView中的属性全部存到ModelAndViewContainer中
mavContainer.addAllAttributes(mav.getModel());
} 接着调用了以下方法 getModelAndView(mavContainer, modelFactory, webRequest); private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//更新Model
modelFactory.updateModel(webRequest, mavContainer);
//如果是json处理方式的,那么这个request已经处理完了,返回null,如果是其他的,需要视图解析的,那么继续。
if (mavContainer.isRequestHandled()) {
return null;
}
//获取model,会根据标识来判断是返回默认model还是重定向model
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
} 一下是获取model的方法
public ModelMap getModel() {
if (useDefaultModel()) {
return this.defaultModel;
}
else {
if (this.redirectModel == null) {
this.redirectModel = new ModelMap();
}
return this.redirectModel;
}
} /**
* Whether to use the default model or the redirect model.
*/
private boolean useDefaultModel() {
return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
} 更新Model
public void updateModel(NativeWebRequest request, ModelAndViewContainer container) throws Exception {
//获取默认的Model,sessionAttribute注释的属性,只有model和modelMap才能用,redirectModel没有用。
ModelMap defaultModel = container.getDefaultModel();
//检查是否已经被清理了,在handlerMethod中可以调用SessionStatus的setComplete方法用于标识要清理数据
if (container.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
//如果没有被清理就将注解中定义要保存的key存到session中
//储存sessionAttribute,这个功能可以用来做缓存
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
}
//如果请求没有结束,并且获取的model是默认的model,那么就更新绑定结果
if (!container.isRequestHandled() && container.getModel() == defaultModel) {
updateBindingResult(request, defaultModel);
}
} public void storeAttributes(WebRequest request, Map<String, ?> attributes) {
for (String name : attributes.keySet()) {
Object value = attributes.get(name);
Class<?> attrType = (value != null) ? value.getClass() : null;
//判断是否是@SessionAttribute定义的属性名和类型,如果是就存到session中
if (isHandlerSessionAttribute(name, attrType)) {
this.sessionAttributeStore.storeAttribute(request, name, value);
}
}
} public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
Assert.notNull(attributeValue, "Attribute value must not be null");
String storeAttributeName = getAttributeNameInSession(request, attributeName);
request.setAttribute(storeAttributeName, attributeValue, WebRequest.SCOPE_SESSION);
} //更新绑定结果
private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
List<String> keyNames = new ArrayList<String>(model.keySet());
for (String name : keyNames) {
Object value = model.get(name);
//将绑定结果,比如校验的结果,用于页面展示
if (isBindingCandidate(name, value)) {
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name; if (!model.containsAttribute(bindingResultKey)) {
WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
model.put(bindingResultKey, dataBinder.getBindingResult());
}
}
}
} 回到DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用拦截器的preHandler方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果没有设置视图,那么使用viewNameTranslator获取默认的视图名
applyDefaultViewName(processedRequest, mv);
//调用拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//如果出现异常就触发拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
//如果出现异常就触发拦截器的afterCompletion方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
} private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
//获取handler
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); //调用异常处理器处理数据。
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
} // Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
} if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
} if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
} //渲染方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
//从request中获取本地信息
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale); View view;
//判断mv中设置的视图是视图名称还是视图对象
if (mv.isReference()) {
// We need to resolve the view name.如果是视图名称,那么通过视图解析器解析获取视图对象{(protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}))
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
} // Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
//调用视图的渲染方法mv.getModelInternal()获取modelMap,我们的设置的参数在里面
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
} InternalResourceViewResolver解析器(jstl) protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
} view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap()); Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
} return view;
} //合并属性
protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) { @SuppressWarnings("unchecked")
//判断是否要暴露路径变量供视图使用
Map<String, Object> pathVars = (this.exposePathVariables ?
(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null); // Consolidate static and dynamic model attributes.
int size = this.staticAttributes.size();
size += (model != null ? model.size() : 0);
size += (pathVars != null ? pathVars.size() : 0); Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);
mergedModel.putAll(this.staticAttributes);
//将暴露的属性合并到modelMap中
if (pathVars != null) {
mergedModel.putAll(pathVars);
}
if (model != null) {
mergedModel.putAll(model);
} // Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
}
//将合并的数据返回
return mergedModel;
} //渲染合并的model
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Expose the model object as request attributes.就是将属性设置到request,如果属性对应的值为空,那么就从request中移除
exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any.
exposeHelpers(request);
//如果路径和当前请求的路径一样,那么就抛出错误
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
//获取请求分发器,request.getDispatcher(diapatcherPath)
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
} // If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(request, response);
} else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
请求转发
rd.forward(request, response);
}
}

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

  1. C# 方法返回值的个数

    方法返回值类型总的来说分为值类型,引用类型,Void 有些方法显示的标出返回值 public int Add(int a,int b) { return a+b; } 有些方法隐式的返回返回值,我们可 ...

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

    在开发过程中,我们不能将ResultSet对象作为方法的返回值,因为Connection连接一旦关闭,在此连接上的会话和在会话上的结果集也将会自动关闭,而Result对象则不会发生这种现象,所以在查询 ...

  3. AJAX JQuery 调用后台方法返回值(不刷新页面)

    AJAX JQuery 调用后台方法返回值(不刷新页面) (1)无参数返回值(本人亲试返回结果不是预期结果) javascript方法: $(function () {             //无 ...

  4. SpringMVC第五篇【方法返回值、数据回显、idea下配置虚拟目录、文件上传】

    Controller方法返回值 Controller方法的返回值其实就几种类型,我们来总结一下-. void String ModelAndView redirect重定向 forward转发 数据回 ...

  5. 关于java字节流的read()方法返回值为int的思考

    我们都知道java中io操作分为字节流和字符流,对于字节流,顾名思义是按字节的方式读取数据,所以我们常用字节流来读取二进制流(如图片,音乐 等文件).问题是为什么字节流中定义的read()方法返回值为 ...

  6. java 反射获取方法返回值类型

    //ProceedingJoinPoint pjp //获取方法返回值类型 Object[] args = pjp.getArgs(); Class<?>[] paramsCls = ne ...

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

    <div id="news-top" class="section"> <h3>Some title</h3> <di ...

  8. eclipse自动生成变量名声明(按方法返回值为本地变量赋值)

    eclipse自动生成变量名声明(按方法返回值为本地变量赋值) ctrl+2+L 这个快捷键可自动补全代码,极大提升编码效率! 注:ctrl和2同时按完以后释放,再快速按L.不能同时按! 比如写这句代 ...

  9. SpringMVC的@RequestMapping和Controller方法返回值

    本节内容: @RequestMapping Controller方法返回值 一.@RequestMapping 通过@RequestMapping注解可以定义不同的处理器映射规则. 1. URL路径映 ...

随机推荐

  1. 使用LinkedList模拟一个堆栈或者队列数据结构。

    堆栈:先进后出 First in last out filo 队列:先进先出 First in last out filo使用LinkedList的方法,addFirst addLast getFir ...

  2. JVM史上最全实践优化没有之一

    JVM史上最全优化没有之一 1.jvm的运行参数 1.1 三种参数类型 1.1.1 -server与-clinet参数 2.1 -X参数 2.1.1 -Xint.-Xcomp.-Xmixed 3.1 ...

  3. 【Linux】一步一步学Linux——虚拟机简介和系统要求(04)

    目录 00. 目录 01. VMware Workstation Pro15介绍 02. Workstation Pro 的主机系统要求 03. 虚拟机网络连接支持 04. 参考 00. 目录 @ 0 ...

  4. Python基础-组织列表

    1.字符串的几个常用方法 name = ''adb lovelace '' name.title() 首字母大写 name.upper() 全部大写 name.lower() 全部小写 2.组织列表操 ...

  5. leadcode的Hot100系列--155. 最小栈

    栈:先入后出,后入先出 像电梯一样,先进入电梯的,走到电梯最深处,后进入电梯的,站在电梯门口, 所以电梯打开的时候,后进入的会先走出来,先进入的会后走出来. push,对应入电梯,把数据往里面压 po ...

  6. JAVA UUID 生成唯一密钥(可随机选择长度)

    /**     * 获得指定数目的UUID      * @param number int 需要获得的UUID数量      * @return String[] UUID数组      */    ...

  7. 屏蔽谷歌浏览器"请停用以开发者模式运行的扩展程序"提示

    目标: 对于强迫症患者那是相当难受~~~ 解决方案: 1:进入chrome://extensions/ 右上角开启开发者模式 点击打包扩展程序: 2:扩展程序目录为选择插件(*.crx解压后)的根目录 ...

  8. Python与C/C++相互调用

    参考链接:https://www.cnblogs.com/yanzi-meng/p/8066944.html

  9. JVM内存结构解析

    月初的时候个人网站到期了,不想再折腾重新建站了,以后还是来第三方博客写文章吧,可以省去很多问题.之前写的文章也不是很多,备份懒得做了,从头开始吧.博文仅仅是用来记录和学习总结,如有错误之处请帮忙指正! ...

  10. C# 实现最小化托盘功能

    winform程序实现最小化托盘显示 1.创建新的解决方案,解决方案名称和路径自定义 2.在解决方案下面新建一个窗体,从左边工具箱,将NotifyIcon拖过去窗体,该控件的作用是:运行程序期间在Wi ...